还在用if else?策略模式了解一下!

2019-08-26 06:21:40来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

还在用if else?策略模式了解一下!

在公司负责的就是订单取消业务,老系统中各种类型订单取消都是通过if else 判断不同的订单类型进行不同的逻辑。在经历老系统的折磨和产品需求的不断变更,决定进行一次大的重构:消灭 if else。

接下来就向大家介绍下是如何消灭 if else。

1. if else模式

@Service
public class CancelOrderService {

    public void process(OrderDTO orderDTO) {
        int serviceType = orderDTO.getServiceType();
        if (1 == serviceType) {
            System.out.println("取消即时订单");
        } else if (2 == serviceType) {
            System.out.println("取消预约订单");
        } else if (3 == serviceType) {
            System.out.println("取消拼车订单");
        }
    }
}

若干个月再来看就是这样的感觉

2. 策略模式

2.1 策略模式实现的Service

@Service
public class CancelOrderStrategyService {

    @Autowired
    private StrategyContext context;

    public void process(OrderDTO orderDTO) {
        OrderTypeEnum orderTypeEnum = OrderTypeEnum.getByCode(orderDTO.getServiceType());
        AbstractStrategy strategy = context.getStrategy(orderTypeEnum);
        strategy.process(orderDTO);
    }
}

简洁的有点过分了是不是!!!

2.2 各种类型策略实现及抽象策略类

下面选取了即时订单和预约订单的策略.

@Service
@OrderTypeAnnotation(orderType = OrderTypeEnum.INSTANT)
public class InstantOrderStrategy extends AbstractStrategy {
    @Override
    public void process(OrderDTO orderDTO) {
        System.out.println("取消即时订单");
    }
}
@Service
@OrderTypeAnnotation(orderType = OrderTypeEnum.BOOKING)
public class BookingOrderStrategy extends AbstractStrategy {
    @Override
    public void process(OrderDTO orderDTO) {
        System.out.println("取消预约订单");
    }
}
public abstract class AbstractStrategy {
    abstract public void process(OrderDTO orderDTO);
}

2.3 策略类型注解

每个策略中增加了注解OrderTypeAnnotation,以标注适用于不同类型的策略内容.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface OrderTypeAnnotation {
    OrderTypeEnum orderType();
}

2.4 策略处理器类StrategyProcessor和策略上下文StrategyContext

其中最为核心的为StrategyProcessor 策略处理器类和StrategyContext 策略上下文,

@Component
public class StrategyProcessor implements BeanFactoryPostProcessor {

    private static final String STRATEGY_PACKAGE = "com.lujiahao.strategy";

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        Map<OrderTypeEnum, Class> handlerMap = Maps.newHashMapWithExpectedSize(3);
        ClassScanner.scan(STRATEGY_PACKAGE, OrderTypeAnnotation.class).forEach(clazz -> {
            OrderTypeEnum type = clazz.getAnnotation(OrderTypeAnnotation.class).orderType();
            handlerMap.put(type, clazz);
        });

        StrategyContext context = new StrategyContext(handlerMap);
        configurableListableBeanFactory.registerSingleton(StrategyContext.class.getName(), context);
    }
}
public class StrategyContext {
    private Map<OrderTypeEnum, Class> strategyMap;

    public StrategyContext(Map<OrderTypeEnum, Class> strategyMap) {
        this.strategyMap = strategyMap;
    }

    public AbstractStrategy getStrategy(OrderTypeEnum orderTypeEnum) {
        if (orderTypeEnum == null) {
            throw new IllegalArgumentException("not fond enum");
        }

        if (CollectionUtils.isEmpty(strategyMap)) {
            throw new IllegalArgumentException("strategy map is empty,please check you strategy package path");
        }

        Class clazz = strategyMap.get(orderTypeEnum);
        if (clazz == null) {
            throw new IllegalArgumentException("not fond strategy for type:" + orderTypeEnum.getCode());
        }

        return (AbstractStrategy) SpringBeanUtils.getBean(clazz);
    }
}
  • 首先会扫描指定包中标有@OrderTypeAnnotation的类
  • 将符合类的对应的枚举值作为key,对应的类作为value,保存在策略Map中
  • 初始化StrategyContext,并注册到spring容器中,同时将策略Map传入其中

我们使用了枚举作为Map中的key,相信大家很少有人这样操作过,不过可以放心操作.通过下面两篇文章解答大家的疑问.

  • 自定义枚举类 Enum 是否可以作为 HashMap 的key
  • Java 在 Map 中使用复杂数据类型作为 Key

3. 总结

策略模式极大的减少if else等模板代码,在提升代码可读性的同时,也大大增加代码的灵活性,添加新的策略即可以满足业务需求.
本人在我司业务中对策略模式的应用得到了很好的验证,从此再也不用担心产品改需求.
用策略模式一时爽,一直用一直爽??!

4. 代码

完整代码

Tips

  • 欢迎收藏和转发,感谢你的支持!(??????)??
  • 欢迎关注我的公众号:庄里程序猿,读书笔记教程资源第一时间获得!


原文链接:https://www.cnblogs.com/HelloDeveloper/p/11390512.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:SpringBoot:实现定时任务

下一篇:springboot工程启动即执行一段代码