策略模式实现的方式也大同小异:主要是定义统一行为(接口或抽象类),并实现不同策略下的处理逻辑(对应实现类)。客户端使用时自己选择相应的处理类,利用工厂或其他方式

实体类

模拟订单类

  1. @Data
  2. public class Order {
  3. /**
  4. * 订单来源
  5. */
  6. private String source;
  7. /**
  8. * 支付方式
  9. */
  10. private String payMethod;
  11. /**
  12. * 订单编号
  13. */
  14. private String code;
  15. /**
  16. * 订单金额
  17. */
  18. private BigDecimal amount;
  19. // ...其他的一些字段
  20. }

业务类

假如对于不同来源(pc端、移动端)的订单需要不同的逻辑处理。
项目中一般会有OrderService这样一个类
如下,里面有一坨if-else的逻辑,目的是根据订单的来源的做不同的处理

1、传统方式

  1. @Service
  2. public class OrderService {
  3. public void orderService(Order order) {
  4. if(order.getSource().equals("pc")){
  5. // 处理pc端订单的逻辑
  6. }else if(order.getSource().equals("mobile")){
  7. // 处理移动端订单的逻辑
  8. }else {
  9. // 其他逻辑
  10. }
  11. }
  12. }

2、策略模式

1.定义处理类OrderHandler

  1. public interface OrderHandler {
  2. void handle(Order order);
  3. }

2.定义一个OrderHandlerType注解

来表示某个类是用来处理何种来源的订单

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Service
  5. public @interface OrderHandlerType {
  6. String source();
  7. }

3.实现

接下来就是实现pc端和移动端订单处理各自的handler,并加上我们所定义的OrderHandlerType注解

  • 移动端处理 ```java @OrderHandlerType(source = “mobile”) public class MobileOrderHandler implements OrderHandler { @Override public void handle(Order order) {
    1. System.out.println("处理移动端订单");
    } }
  1. - pc端处理
  2. ```java
  3. @OrderHandlerType(source = "pc")
  4. public class PCOrderHandler implements OrderHandler {
  5. @Override
  6. public void handle(Order order) {
  7. System.out.println("处理PC端订单");
  8. }
  9. }

4.使用

以上准备就绪后,就是向spring容器中注入各种订单处理的handler,
并在OrderService.orderService方法中,通过策略(订单来源)去决定选择哪一个OrderHandler去处理订单。

  1. @Service
  2. public class OrderService {
  3. private Map<String, OrderHandler> orderHandleMap;
  4. @Autowired
  5. public void setOrderHandleMap(List<OrderHandler> orderHandlers) {
  6. // 注入各种类型的订单处理类
  7. orderHandleMap = orderHandlers.stream().collect(
  8. Collectors.toMap(orderHandler -> AnnotationUtils.findAnnotation(orderHandler.getClass(), OrderHandlerType.class).source(),
  9. v -> v, (v1, v2) -> v1));
  10. }
  11. public void orderService(Order order) {
  12. // ...一些前置处理
  13. // 通过订单来源确定对应的handler
  14. OrderHandler orderHandler = orderHandleMap.get(order.getSource());
  15. orderHandler.handle(order);
  16. // ...一些后置处理
  17. }
  18. }

在OrderService中,维护了一个orderHandleMap
它的key为订单来源,value为对应的订单处理器Handler。
通过@Autowired去初始化orderHandleMap。

这样一来,OrderService.orderService里的一坨if-else不见了,取而代之的仅仅是两行代码。
即,先从orderHandleMap中根据订单来源获取对应的OrderHandler,然后执行OrderHandler.handle方法即可。

这种做法的好处是,不论以后业务如何发展致使订单来源种类增加,OrderService的核心逻辑不会改变,我们只需要实现新增来源的OrderHandler即可,且团队中每人开发各自负责的订单来源对应的OrderHandler即可,彼此间互不干扰

优化

现在回过头看orderHandleMap这个Map,它的key是订单来源,
假如,我们想通过订单来源+订单支付方式这两个属性来决定到底使用哪一种OrderHandler怎么办?
比如PC端支付宝支付的订单是一种处理逻辑(PCAliPayOrderHandler),
PC端微信支付的订单是另外一种处理逻辑(PCWeChatOrderHandler),
对应的还有移动端支付宝支付(MobileAliPayOrderHandler)和移动端微信支付(MobileWeChatOrderHandler)

这时候我们的key应该存什么呢,可能有人会说,我直接存订单来源+订单支付方式组成的字符串不就行了吗?
确实可以,但是如果这时业务逻辑又变了(向pm低头),
PC端支付宝支付和微信支付是同一种处理逻辑,而移动端支付宝支付和微信支付是不同的处理逻辑,
那情况就变成了PCAliPayOrderHandler和PCWeChatOrderHandler这两个类是同一套代码逻辑。
我们干掉了if-else,但却造出了两份相同的代码

查看注解的定义和反向代理,可以得知
为什么不把key的类型设置为OrderHandlerType?就像这样。
private Map<OrderHandlerType, OrderHandler> orderHandleMap;

如此一来,不管决定订单处理器orderhandler的因素怎么变,我们便可以以不变应万变,如下

  1. public class OrderService {
  2. private Map<OrderHandlerType, OrderHandler> orderHandleMap;
  3. @Autowired
  4. public void setOrderHandleMap(List<OrderHandler> orderHandlers) {
  5. // 注入各种类型的订单处理类
  6. orderHandleMap = orderHandlers.stream().collect(
  7. Collectors.toMap(orderHandler -> AnnotationUtils.findAnnotation(orderHandler.getClass(), OrderHandlerType.class),
  8. v -> v, (v1, v2) -> v1));
  9. }
  10. // ...省略
  11. }

我们怎么根据order的来源和支付方式去orderHandleMap里获取对应的OrderHandler呢?
问题变成了如何关联order的来源和支付方式与OrderHandlerType注解。
还记得刚才所说的注解就是个接口吗,既然是个接口,我们自己实现一个类不就完事了么,
这样就把order的来源和支付方式与OrderHandlerType注解关联起来了。说干就干,现在我们有了这么一个类,

  1. public class OrderHandlerTypeImpl implements OrderHandlerType {
  2. private String source;
  3. private String payMethod;
  4. OrderHandlerTypeImpl(String source, String payMethod) {
  5. this.source = source;
  6. this.payMethod = payMethod;
  7. }
  8. @Override
  9. public String source() {
  10. return source;
  11. }
  12. @Override
  13. public String payMethod() {
  14. return payMethod;
  15. }
  16. @Override
  17. public Class<? extends Annotation> annotationType() {
  18. return OrderHandlerType.class;
  19. }
  20. @Override
  21. public int hashCode() {
  22. int hashCode = 0;
  23. hashCode += (127 * "source".hashCode()) ^ source.hashCode();
  24. hashCode += (127 * "payMethod".hashCode()) ^ payMethod.hashCode();
  25. return hashCode;
  26. }
  27. @Override
  28. public boolean equals(Object obj) {
  29. if (!(obj instanceof OrderHandlerType)) {
  30. return false;
  31. }
  32. OrderHandlerType other = (OrderHandlerType) obj;
  33. return source.equals(other.source()) && payMethod.equals(other.payMethod());
  34. }
  35. }

具体的业务逻辑如下:

  1. public void orderService(Order order) {
  2. // ...一些前置处理
  3. // 通过订单来源确以及支付方式获取对应的handler
  4. OrderHandlerType orderHandlerType = new OrderHandlerTypeImpl(order.getSource(), order.getPayMethod());
  5. OrderHandler orderHandler = orderHandleMap.get(orderHandlerType);
  6. orderHandler.handle(order);
  7. // ...一些后置处理
  8. }

这样以来,不管以后业务怎么发展,OrderService核心逻辑不会改变,只需要扩展OrderHandler即可