• spring+策略模式


    需求: 这里虚拟一个业务需求,让大家容易理解。假设有一个订单系统,里面的一个功能是根据订单的不同类型作出不同的处理。

    1. 常规代码实现 

    1.1 实体类

    import lombok.Data;
    
    import java.math.BigDecimal;
    
    @Data
    public class OrderDTO {
        private String code;
        private BigDecimal price;
        /**
         * 订单类型
         * 1: 普通订单
         * 2: 团购订单
         * 3: 促销订单
         */
        private String type;
    }

    1.2  接口类

    import qinfeng.zheng.strategy.dto.OrderDTO;
    
    public interface IOrderService {
        /**
         * 根据订单类型做出相应的处理
         *
         * @param orderDTO
         * @return
         */
        String handle(OrderDTO orderDTO);
    
    }

    1.3 接口实现 

    import org.springframework.stereotype.Service;
    import qinfeng.zheng.strategy.dto.OrderDTO;
    import qinfeng.zheng.strategy.service.IOrderService;
    
    @Service
    public class V1OrderServiceImpl implements IOrderService {
        @Override
        public String handle(OrderDTO orderDTO) {
            String type = orderDTO.getType();
            if (type.equals("1")) {
                return "处理普通订单成功";
            }
            if (type.equals("2")) {
                return "处理团购订单成功";
            }
            if (type.equals("3")) {
                return "处理促销订单成功";
            }
            return "订单类型不存在";
        }
    }

    1.4 结论

      不用说, 这代码 很low. 

    2. 使用策略模式实现此功能

       策略模式的关键就是一个抽象处理类,配上一个持有这个抽象处理类实例的context. 下面是代码的具体的实现 

    2.1 抽象类

    import qinfeng.zheng.strategy.dto.OrderDTO;
    
    public abstract class AbsHandler {
        abstract public String handle(OrderDTO orderDTO);
    }

    2.2 具体实现类

    import org.springframework.stereotype.Component;
    import qinfeng.zheng.strategy.anno.HandlerType;
    import qinfeng.zheng.strategy.dto.OrderDTO;
    
    @Component
    @HandlerType("1")
    public class NormalHandler extends AbsHandler {
        @Override
        public String handle(OrderDTO orderDTO) {
            return "处理普通订单";
        }
    }
    import org.springframework.stereotype.Component;
    import qinfeng.zheng.strategy.anno.HandlerType;
    import qinfeng.zheng.strategy.dto.OrderDTO;
    
    @Component
    @HandlerType("2")
    public class GroupHandler extends AbsHandler {
        @Override
        public String handle(OrderDTO orderDTO) {
            return "处理团购订单";
        }
    }
    import org.springframework.stereotype.Component;
    import qinfeng.zheng.strategy.anno.HandlerType;
    import qinfeng.zheng.strategy.dto.OrderDTO;
    
    @Component
    @HandlerType("3")
    public class PromotionHandler extends AbsHandler {
        @Override
        public String handle(OrderDTO orderDTO) {
            return "处理促销订单";
        }
    }

    2.3 context类

    public class HandlerContext {
        private Map<String, Class> handlerMap;
    
        public HandlerContext(Map<String, Class> handlerMap) {
            this.handlerMap = handlerMap;
        }
    
        public AbsHandler getInstance(String type) throws Exception {
            Class aClass = handlerMap.get(type);
            if (aClass == null) {
                throw new IllegalArgumentException("not found handler type :" + type);
            }
            return (AbsHandler) aClass.newInstance();
        }
    
    }

    2.3 自定义注解类

    import java.lang.annotation.*;
    
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface HandlerType {
        String value();
    }

    2.4 自定义BeanFactory后置处理类,将HandlerContext注册到spring容器中

    import cn.hutool.core.lang.ClassScanner;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.stereotype.Component;
    import qinfeng.zheng.strategy.anno.HandlerType;
    import qinfeng.zheng.strategy.context.HandlerContext;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Component
    public class HandlerProcessor implements BeanFactoryPostProcessor {
        private static final String HANDLE_PACKAGE = "qinfeng.zheng.strategy";
    
        /**
         * 扫描@HandlerType注解,初始化HandlerContext, 并将其注册到spring容器中
         * @param beanFactory  bean工厂呀......
         * @throws BeansException
         */
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            Map<String, Class> handlerMap = new HashMap<>();
            ClassScanner.scanPackageByAnnotation(HANDLE_PACKAGE,HandlerType.class).forEach(aClass -> {
                String value = aClass.getAnnotation(HandlerType.class).value();
                handlerMap.put(value, aClass);
            });
            // 初始化HandlerContext
            HandlerContext handlerContext = new HandlerContext(handlerMap);
            // 手动将HandlerContext注册到spring容器中
            beanFactory.registerSingleton(HandlerContext.class.getName(), handlerContext);
        }
    }

    2.4 修改IOrderService接口实现 

    @Service
    public class V2OrderServiceImpl implements IOrderService {
    
        @Autowired
        private HandlerContext handlerContext;
    
        @Transactional
        @Override
        public String handle(OrderDTO orderDTO) throws Exception {
            AbsHandler handler = handlerContext.getInstance(orderDTO.getType());
            return handler.handle(orderDTO);
        }
    }

    2.5 写个controller测试一下

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import qinfeng.zheng.strategy.dto.OrderDTO;
    import qinfeng.zheng.strategy.service.IOrderService;
    
    @RestController
    public class OrderController {
        /**
         * @Autowired自定根据 v2OrderServiceImpl 名称 适配 V2OrderServiceImpl这个实现类
         */
        @Autowired
        private IOrderService v2OrderServiceImpl;
        
        @GetMapping("/handle")
        public String handler(OrderDTO orderDTO) throws Exception {
            return v2OrderServiceImpl.handle(orderDTO);
        }
    }

    好, 代码写完了,使用策略模式之后,代码的扩展性确实增强,若订单类型发生改变,只需添加AbsHandler的实现类即可,其它都不需要变。

    但是,我觉得这代码并不好呀, 这样操作,实现策略模式的代码太多了。 其二,我使用了 aClass.newInstance()反射方式创建一个具体的Handler对象,这儿并没有使用spring的代理功能,所以如果在AbsHandler#handle方法上添加事务,是不会生效的,只能在V2OrderServiceImpl#handle方法添加事务。

    不过这个示例也让我真实体验了一把 BeanFactoryPostProcessor 这个接口的功能, 以后如果有需要手动注册bean的场景,可以考虑使用这个接口,但是这个接口的主要功能并不注册bean, 而是修改管理bean工厂内所有的beandefinition(未实例化)数据,并且随心所欲的修改属性。 

    此外,ClassScanner这个类使用hutool类库。

    以上示例代码大多来自“java那些事儿”

  • 相关阅读:
    Unity调试模式设置辅助线是否可见
    Gizmos绘制塔防游戏网格
    JS offsetparent 问题
    JS 图像延迟加载
    JS image对象
    JS 瀑布流
    JS 对象
    JS node
    Vue+element 实现表格的增加行、根据索引删除行的功能
    Java的集合框架
  • 原文地址:https://www.cnblogs.com/z-qinfeng/p/12210665.html
Copyright © 2020-2023  润新知