在公司负责的就是订单取消业务, 老系统中各种类型订单取消都是通过 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. 代码
完整代码
欢迎大家关注
欢迎大家关注
来源: https://www.cnblogs.com/HelloDeveloper/p/11390512.html