zoukankan      html  css  js  c++  java
  • springboot中使用自定义注解实现策略模式,去除工厂模式的switch或ifelse,实现新增策略代码零修改

    前言 思路与模拟业务

    源码地址 https://gitee.com/houzheng1216/springboot

    整体思路就是通过注解在策略类上指定约定好的type,项目启动之后将所有有注解的type获取到,根据type存储,然后在业务中根据type获取对应的策略即可

    模拟订单业务,根据订单的type,需要不同的处理逻辑,比如,免费订单,半价订单等,下面是项目结构:

    一 策略接口和实现

    /**
     * 处理订单策略
     */
    public interface OrderStrategy {
    
        void handleOrder(Order order);
    }
    @Component
    @HandlerOrderType(Order.FREE) //使用注解标明策略类型
    public class FreeOrderStrategy implements OrderStrategy {
        @Override
        public void handleOrder(Order order) {
            System.out.println("----处理免费订单----");
        }
    }
    @Component
    @HandlerOrderType(Order.HALF)
    public class HalfOrderStrategy implements OrderStrategy {
        @Override
        public void handleOrder(Order order) {
            System.out.println("----处理半价订单----");
        }
    }
    @Component
    @HandlerOrderType(Order.DISCOUT)
    public class DiscoutOrderStrategy implements OrderStrategy {
        @Override
        public void handleOrder(Order order) {
            System.out.println("----处理打折订单----");
        }
    }

    二 自定义策略注解

    @Target(ElementType.TYPE)  //作用在类上
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited  //子类可以继承此注解
    public @interface HandlerOrderType {
        /**
         * 策略类型
         * @return
         */
        int value();
    }

    此处只能用基本类型或者String,约定的类型放在Order实体类里

    三 业务实体

    public class Order {
        public static final int FREE=1; //免费订单
        public static final int HALF=2; //半价订单
        public static final int DISCOUT=3; //打折订单
        private String name;
        private Double price;
        private Integer type;//订单类型
        public static Order build(){
            return new Order();
        }
     

    四 核心功能实现

    主要就是这一块实现策略逻辑

    /**
     * 根据订单类型返回对应的处理策略
     */
    @Component
    public class HandlerOrderContext {
        @Autowired
        private ApplicationContext applicationContext;
        //存放所有策略类Bean的map
        public static Map<Integer, Class<OrderStrategy>> orderStrategyBeanMap= new HashMap<>();
    
        public OrderStrategy getOrderStrategy(Integer type){
            Class<OrderStrategy> strategyClass = orderStrategyBeanMap.get(type);
            if(strategyClass==null) throw new IllegalArgumentException("没有对应的订单类型");
            //从容器中获取对应的策略Bean
            return applicationContext.getBean(strategyClass);
        }
    }
    /**
     * 策略核心功能,获取所有策略注解的类型
     * 并将对应的class初始化到HandlerOrderContext中
     */
    @Component
    public class HandlerOrderProcessor implements ApplicationContextAware {
        /**
         * 获取所有的策略Beanclass 加入HandlerOrderContext属性中
         * @param applicationContext
         * @throws BeansException
         */
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            //获取所有策略注解的Bean
            Map<String, Object> orderStrategyMap = applicationContext.getBeansWithAnnotation(HandlerOrderType.class);
            orderStrategyMap.forEach((k,v)->{
                Class<OrderStrategy> orderStrategyClass = (Class<OrderStrategy>) v.getClass();
                int type = orderStrategyClass.getAnnotation(HandlerOrderType.class).value();
                //将class加入map中,type作为key
                HandlerOrderContext.orderStrategyBeanMap.put(type,orderStrategyClass);
            });
        }
    }

    五 业务service使用

    @Component
    public class OrderServiceImpl implements OrderService {
        @Autowired
        HandlerOrderContext handlerOrderContext;
        @Override
        public void handleOrder(Order order) {
            //使用策略处理订单
            OrderStrategy orderStrategy = handlerOrderContext.getOrderStrategy(order.getType());
            orderStrategy.handleOrder(order);
        }
    }

    很简单,业务代码以后基本不用再修改,不管添加多少策略或者需求变更多少次

    六 controller测试

    @RestController
    @RequestMapping("/order")
    public class OrderController {
        @Autowired
        OrderService orderService;
        @GetMapping("/handler/{type}")
        public void handleOrder(@PathVariable Integer type){
            Order order = Order.build()
                    .add("name", "微信订单")
                    .add("price", 99.9)
                    .add("type", type);
            orderService.handleOrder(order);
        }
    }

    使用链式风格构造对象

    测试:

    再添加策略添加实现类,启用注解即可!

    省去了工厂模式,直接用注解实现,避免修改工厂类,

    这里贴一个我们之前项目的工厂类实现:

    如果再添加策略还是会有轻微的改动!

  • 相关阅读:
    省市区distpicker,从数据库里查出来回显,动态绑定
    ajax请求里面的success和error里面的layer.msg,status: "parsererror",刷新父界面,碰到的一些问题
    排序算法时间和空间算法度
    适配器模式
    守护线程
    工厂模式之简单工厂模式、工厂模式、抽象工厂
    ArrayList源码分析和缩减版手写ArrayList(jdk1.8和1.9)
    HashMap排序题
    二进制中1的个数
    anaconda指定镜像源,解决conda下载速度慢失败问题
  • 原文地址:https://www.cnblogs.com/houzheng/p/10911462.html
Copyright © 2011-2022 走看看