美文网首页Java 杂谈Java设计模式
还在用if else?策略模式了解一下!

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

作者: 后端小哥 | 来源:发表于2019-05-25 15:22 被阅读0次

    小编在公司负责的就是订单取消业务,老系统中各种类型订单取消都是通过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("取消拼车订单");
            }
        }
    }
    

    若干个月再来看就是这样的感觉
    [图片上传失败...(image-5326cf-1558768863542)]

    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,相信大家很少有人这样操作过,不过可以放心操作.通过下面两篇文章解答大家的疑问.

    3. 总结

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

    4. 代码

    完整代码


    欢迎大家关注😁


    公众号二维码.jpg

    相关文章

      网友评论

        本文标题:还在用if else?策略模式了解一下!

        本文链接:https://www.haomeiwen.com/subject/lxfzzqtx.html