阿里巴巴开发者手册上只提到了超过三层的if-else的逻辑判断代码可以使用策略模式来实现,但是并没有告诉你怎么实现。下面介绍一下常规的实现方式。
实现方式
需求背景
在做订单时效判定时,要根据订单的类型做不同的操作,目前主要包括四种类型:
- 全推即时单,对应枚举对象NORMAL_CANCELORDER
- 全推预订单,对应枚举对象BOOK_CANCELORDER
- 选推即时单,对应枚举对象XUANTUI_CANCELORDER
- 选推预订单,对应枚举对象BOOK_XUANTUI_CANCELORDER
一、定义策略接口
public enum TimerJudgeBizTypeEnum {
NORMAL_CANCELORDER(1, "全推即时单"),
BOOK_CANCELORDER(2, "BOOK_CANCELORDER"),
XUANTUI_CANCELORDER(3, "选推即时单"),
BOOK_XUANTUI_CANCELORDER(4, "选推预订单");
private int code;
private String desc;
TimerJudgeBizTypeEnum(int code, String desc){
this.code = code;
this.desc = desc;
}
}
public interface TimerJudgeService {
boolean isMatched(TimerJudgeBizTypeEnum bizTypeEnum);
Response<T> getTimerJudge(Long orderId);
}
定义了策略的接口,包括两个方法:
- isMatched()用于获取匹配的策略类型;
- getTimerJudge()用于处理具体的策略逻辑
二、具体的策略实现类
全推即时单的业务逻辑处理:
@Service
public class NormalCancelOrderJudgeTimerHandler implements TimerJudgeService {
@Override
public boolean isMatched(TimerJudgeBizTypeEnum bizTypeEnum) {
return TimerJudgeBizTypeEnum.NORMAL_CANCELORDER.equals(bizTypeEnum);
}
@Override
public Response<T> getTimerJudge(Long orderId) {
System.out.println("全推即时单执行业务逻辑ing。。。。");
return Response.success("返回结果");
}
}
全推预订单的业务逻辑处理:
@Service
public class BookCancelOrderJudgeTimerHandler implements TimerJudgeService {
@Override
public boolean isMatched(TimerJudgeBizTypeEnum bizTypeEnum) {
return TimerJudgeBizTypeEnum.BOOK_CANCELORDER.equals(bizTypeEnum);
}
@Override
public Response<T> getTimerJudge(Long orderId) {
System.out.println("全推预订单执行业务逻辑ing。。。。");
return Response.success("返回结果");
}
}
其他两个场景类似
三、建立manager处理类
@Service
public class TimerJudgeManager implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
private List<TimerJudgeService> handlers = new ArrayList<>();
public TimerJudgeService doGetHandle(TimerJudgeBizTypeEnum bizTypeEnum) {
for (TimerJudgeService handler : handlers) {
if (handler.isMatched(bizTypeEnum)) {
return handler;
}
}
return null;
}
@Override
public void afterPropertiesSet() {
for (TimerJudgeService handle : applicationContext.getBeansOfType(TimerJudgeService.class).values()) {
handlers.add(handle);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
四、 测试类
@Service
public class TimerJudgeTest {
@Autowired
private TimerJudgeManager timerJudgeManager;
public Response<T> test(TimerJudgeBizTypeEnum bizTypeEnum) {
TimerJudgeService timerJudgeService = doGetHandle(bizTypeEnum);
System.out.println("返回结果" + timerJudgeService);
}
}
可以发现,通过让TimerJudgeManager实现ApplicationContextAware和InitializingBean两个接口,然后在afterPropertiesSet方法中就可以基于Spring容器启动时自动注册所有的策略实现类到handlers这个hashmap容器中。然后在使用过程中根据不同的业务场景直接doGetHandle方法来获得具体的策略实现类。
综上,TimerJudgeManager只负责获取对应的handler实现类,各个handler实现类只负责实现各自的业务逻辑,达到了“高内聚低耦合”的效果。并且,当需要新增策略类时,只需要实现接口即可。
优缺点
优点
- 避免了大量的if-else语句导致的耦合性太高、代码比较臃肿、维护代价很高;
- 遵循开闭原则,实现代码的解耦合。当新增一种策略场景时,仅仅新增一个实现类即可,扩展性非常好,而且每个实现类符合单一职责原则。
缺点:
- 要求客户端必须知道所有的策略类,然后再调用的时候传入对应的策略类型;
使用场景
- 对客户端隐藏具体策略实现细节,彼此完全独立;
- 多个实现类只是业务细节不同,在运行时要动态选择具体要执行的类;