应用场景
我的理解:策略模式解决 特别多 if 的问题 非常有效。
假设业务中有如下场景:
水果摊要定价 苹果8元/斤
,香蕉5元/斤
。
用最简单的代码实现应该是:
public static void main(String[] args) {
String fruit = "";
double price = 0.0d;
if ("苹果".equals(fruit)) {
price = 8.0;
} else if ("香蕉".equals(fruit)) {
price = 5.0;
}
System.out.println(price);
return;
}
假如有100种水果,那就得是有100个 if...else if...else
的代码串。这样的代码可读性极差,特别在每个 if 中逻辑复杂的话,维护起来更是要吐血。
卫语句
于是你就想着能不能让这串代码好看一些,可能就会有下面的代码:
public static void main(String[] args) {
String fruit = "";
double price = 0.0d;
if ("苹果".equals(fruit)) {
price = 8.0;
System.out.println(price);
return;
}
if ("香蕉".equals(fruit)) {
price = 5.0;
System.out.println(price);
return;
}
}
这玩意儿叫做卫语句。
卫语句让代码可读性变高了,看起来每个 if 分支独立管理,维护性有一定变高。这种写法对于大量 if 的业务是一种可行的解决方案。
总的来说就是使用成本低,但是维护性提升有限。
策略模式
简单 demo
为了提高维护性,那就得另想法子,当你搜索的时候,策略模式肯定会出现在你的搜索结果中。
下面的策略模式 demo 也是常见的:
第一步:先搞一个**抽象出来的业务(描述价格)**的接口
/**
* 抽象策略,水果接口
*/
public interface Fruit {
/**
* 输出对应的价格
*/
void price();
}
第二步:声明一个类,用来调用水果接口。当你传入不同的水果类型时,printFruitPrice()
这个方法会执行对应策略定义的内容
/**
* 策略环境,输出水果价格
*/
public class FruitPrice {
private Fruit fruit;
public FruitPrice(Fruit fruit) {
this.fruit = fruit;
}
/**
* 输出水果的价格
*/
public void printFruitPrice() {
fruit.price();
}
}
第三步:写策略,根据不同的水果制定不同的价格
/**
* 具体策略,苹果
*/
public class Apple implements Fruit {
@Override
public void price() {
System.out.println("苹果8元/斤");
}
}
/**
* 具体策略,香蕉
*/
public class Banana implements Fruit{
@Override
public void price() {
System.out.println("香蕉5元/斤");
}
}
第四步:调用策略
/**
* 客户端使用策略模式
*/
public class Client {
public static void main(String[] args) {
Fruit apple = new Apple();
new FruitPrice(apple).printFruitPrice();
}
}
/**
* 执行结果 苹果8元/斤
*/
到这边为止,策略模式一个简单的demo就实现了。
但是,现在的项目中基本都是使用 springboot,在 springboot 中还是这样使用策略模式,就显得段位有点低了,也不是说装逼,就是没有发挥 springboot 的优势,属于“丢西瓜捡芝麻”的行为。
集成springboot的策略模式
第一步:还是先搞一个**抽象出来的业务(描述价格)**的接口
/**
* 抽象策略,水果接口
*/
public interface FruitStrategyService {
/**
* 输出对应的价格
*/
void price();
}
第二步:声明一个类,用来调用水果接口。
这边修改了获取策略的方式,上面的例子是使用构造方法调用策略,而这边在项目启动的时候就把策略类注册到了 spring 容器中,需要使用的时候根据 spring 实例名称去调用。
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class FruitStrategyContext {
// 用来存放所有策略的容器
private final Map<String, FruitStrategyService> strategyMap = new ConcurrentHashMap<>();
// 存放策略类的 spring 实例
public FruitStrategyContext(Map<String, FruitStrategyService> strategyMap) {
this.strategyMap.clear();
strategyMap.forEach((k, v) -> this.strategyMap.put(k, v));
}
/**
* 输出水果的价格
*/
public void printFruitPrice(String strategy) {
this.strategyMap.get(strategy).price();
}
}
第三步:写策略,根据不同的水果制定不同的价格
import org.springframework.stereotype.Component;
/**
* 具体策略,苹果
*/
@Component("appleImpl")
public class AppleImpl implements FruitStrategyService {
@Override
public void price() {
System.out.println("苹果8元/斤");
}
}
第四步:调用策略
@Autowired
private FruitStrategyContext strategyContext;
public void getPrice(){
strategyContext.printFruitPrice("appleImpl");
}