工厂模式是解耦对象的创建和使用,观察者模式是解耦观察者和被观察者。策略模式跟两者类似,也能起到解耦的作用,解耦的是策略的定义、创建、使用这三部分。
通常的使用方式
**
1.策略定义
**
一个策略接口和一组实现这个接口的策略类。因为所有的策略类都实现相同的接口,所以,客户端代码基于接口而非实现编程,可以灵活地替换不同的策略。
public interface Strategy {
void algorithm();
}
public class StrategyA implements Strategy {
@Override
public void algorithm() {
//具体的算法...
}
}
public class StrategyB implements Strategy {
@Override
public void algorithm() {
//具体的算法...
}
}
2.策略创建
一组策略,使用时一般通过type来判断创建哪个策略。
工厂封装创建逻辑,对客户端屏蔽创建细节
public class StrategyFactory {
private static final Map<String, Strategy> strategies = new HashMap<>();
static {
strategies.put("A", new StrategyA());
strategies.put("B", new StrategyB());
}
public static Strategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
return strategies.get(type);
}
}
如果策略类是无状态的,不包含成员变量,只是纯粹的算法实现,这样的策略对象是可以被共享使用的,使用map缓存
如果策略类是有状态的,根据业务场景的需要,我们希望每次从工厂方法中,获得的都是新创建的策略对象,而不是缓存好可共享的策略对象,则:
public class StrategyFactory {
public static Strategy getStrategy(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("type should not be empty.");
}
if (type.equals("A")) {
return new StrategyA();
} else if (type.equals("B")) {
return new StrategyB();
}
return null;
}
}
3.策略的使用
最常见的是运行时动态确定使用哪种策略,这也是策略模式最典型的应用场景。
Strategy strategy=StrategyFactory.getStrategy(type)
简便的使用方式
1.策略定义
public interface Strategy {
//用来匹配策略
boolean match(String type);
String algorithm();
}
public class StrategyA implements Strategy {
@Override
public boolean match(String type) {
return "A".equals(type);
}
@Override
public String algorithm() {
//具体的算法...
return "this is A";
}
}
public class StrategyB implements Strategy {
@Override
public boolean match(String type) {
return "B".equals(type);
}
@Override
public String algorithm() {
//具体的算法...
return "this is B";
}
}
//默认执行的策略
public class DefaultStrategy implements Strategy {
@Override
public boolean match(String type) {
return false;
}
@Override
public String algorithm() {
return "this is 默认方法";
}
}
2.策略使用
@Autowired
private List<Strategy> strategyList;
@Autowired
private DefaultStrategy defaultStrategy;
@Test
public void test_Strategy(){
String type="A";
//直接使用lamba表达式,match匹配执行Strategy
String result=strategyList.stream()
.filter(strategy -> strategy.match(type))
.findFirst()
.orElse(defaultStrategy)
.algorithm();
}
输出result="this is A";
实战代码优化
原代码写法
if (TradeChannelTypeEnum.RAPID_SEND.getType() == tradeChannel) {
result = rapidSendInvSaleMatch.match(dbEntity, EnumsMatchType.NORMAL.getType(), tradeChannel..);
} else if (TradeChannelTypeEnum.FLASH_SEND.getType() == tradeChannel) {
result = flashSendInvSaleMatch.match(dbEntity, EnumsMatchType.NORMAL.getType(), tradeChannel..);
} else if (TradeChannelTypeEnum.BRAND_OFFER.getType() == tradeChannel) {
result = brandOfferInvSaleMatch.match(dbEntity, EnumsMatchType.NORMAL.getType(), tradeChannel..);
} else {
result = defaultInvSaleMatch.match(dbEntity, EnumsMatchType.NORMAL.getType(), tradeChannel..);
}
可以看出,在业务增加的情况下,不断增加if-else,增加 InvSaleMatch service。根据不同的tradeChannel选择不同的 **InvSaleMatch (**InvSaleMatch都继承自AbsInvSaleMatch),可直接使用策略模式。
优化之后
//AbsInvSaleMatch增加 tradeChannelMatch方法
boolean tradeChannelMatch(int tradeChannel);
//各个InvSaleMatch 实现类里判断tradeChannel,用来替代之前代码里的if判断
@Autowired
private List<AbsInvSaleMatch> saleMatchList;
result = saleMatchList.stream().filter(hander -> hander.tradeChannelMatch(tradeChannel)).findFirst()
.orElse(defaultInvSaleMatch)
.match(dbEntity, EnumsMatchType.NORMAL, tradeChannel..);