美文网首页
装饰器模式在项目中的实际运用

装饰器模式在项目中的实际运用

作者: 小胖学编程 | 来源:发表于2020-11-04 18:21 被阅读0次

    1. 理论

    装饰器(Decorator)模式:允许向一个现有的对象添加新的功能,同时又不改变器其结构。

    这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供额外的功能。

    意图:Decorator模式采用对象组合而非继承的方式,实现了动态的扩展对象功能的能力。而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“大量子类”的问题。

    使用场景:在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。处理那些可以撤销的职责。

    1. 当不能采用生成子类的方式进行扩展时。一种情况是:可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
    2. (重写源码)因为类定义被隐藏,或类定义不能用于生成子类。
    结构图.png

    代理模式和装饰器模式的区别

    在装饰器模式中,必须有被装饰的类和装饰的类。代理模式一定是自身持有这个对象,不需要从外部传入。而装饰模式一定是从外部传入(即代理模式的目标对象不对外,代理对象全权处理;装饰器模式是辅助,目标仍然可以对外提供服务,装饰器模式只是增强作用),并且可以没有顺序,按照代码的试卷需要随意挑换顺序。

    从使用上,代理模式注重隔离限制,让外部不能方法实际调用对象,比如权限控制,装饰模式注重的是功能的扩展,在一个方法下实现更多的功能。

    2. 项目实际用法

    接口类型(Component):给出一个抽象类接口,以规范准备接收附加责任的对象

    /**
     * 具体的业务接口
     */
    public interface MappingBusinessService {
    
        /**
         * 接口的方法
         */
        ItemAnswerResp assembleItemAndAnswer(OriResult oriResult, PlanInfoDto planInfoDto);
    }
    

    具体子类(ConcreteCompoent):定义一个业务接口的具体实现:

    而实际业务中,可以多种设计模式组合使用,此处使用“模板方法模式”来实现。

    /**
     * 模板方式——将大逻辑拆分为小逻辑。
     */
    @Slf4j
    public abstract class AbstractMappingBusinessService implements MappingBusinessService {
        @Override
        public ItemAnswerResp assembleItemAndAnswer(OriResult oriResult, PlanInfoDto planInfoDto) {
            //数据校验
            validateHandler(planInfoDto);
            //数据准备
            prepareHandler(planInfoDto);
            //获取做的记录
            List<ItemAnswerDto> itemAnswerInfo = getItemAnswerInfo(planInfoDto);
            log.info(JSON.toJSONString(itemAnswerInfo));
            return null;
        }
    
        /**
         * 子类必须实现的抽象方法
         */
        public abstract List<ItemAnswerDto> getItemAnswerInfo(PlanInfoDto planInfoDto);
    
        /**
         * 校验器
         */
        protected void validateHandler(PlanInfoDto planInfoDto){
        }
    
        /**
         * 数据准备器
         */
        protected void prepareHandler(PlanInfoDto planInfoDto){
            log.info("AbstractMappingBusinessService的数据准备");
        }
    
    }
    
    /**
     * 二级父类
     */
    @Slf4j
    public abstract class AbstractSimpleMappingBusinessService extends AbstractMappingBusinessService {
    
        /**
         * 某些业务场景下,可能存在多级父类情况
         */
        protected void prepareHandler(PlanInfoDto planInfoDto) {
            super.prepareHandler(planInfoDto);
            log.info("AbstractSimpleMappingBusinessService的数据准备");
        }
    
    }
    

    具体的子类,子类已经在Spring容器中。

    /**
     * 具体子类
     */
    @Service
    @Slf4j
    public class MappingBusinessServiceImpl3 extends AbstractSimpleMappingBusinessService {
        @Override
        public List<ItemAnswerDto> getItemAnswerInfo(PlanInfoDto planInfoDto) {
            ItemAnswerDto itemAnswerDto = new ItemAnswerDto();
            itemAnswerDto.setName("亚瑟");
            ItemAnswerDto itemAnswerDto2 = new ItemAnswerDto();
            itemAnswerDto2.setName("韩信");
            return Arrays.asList(itemAnswerDto, itemAnswerDto2);
        }
    }
    

    装饰器类

    装饰器类和具体实现继承的是同一接口。

    /**
     * 装饰器
     */
    @Slf4j
    public class LogMappingBusinessDecorator implements MappingBusinessService {
    
        private MappingBusinessService mappingBusinessService;
    
        public LogMappingBusinessDecorator(MappingBusinessService mappingBusinessService) {
            this.mappingBusinessService = mappingBusinessService;
        }
    
        @Override
        public ItemAnswerResp assembleItemAndAnswer(OriResult oriResult, PlanInfoDto planInfoDto) {
            log.info("日志装饰器增加可以被撤销的职责");
            return mappingBusinessService.assembleItemAndAnswer(oriResult, planInfoDto);
        }
    }
    

    疑问?装饰器类能实现抽象类接口吗?

    是可以的。装饰器类可以实现抽象类。来动态的扩展抽象类。

    但是实现的抽象父类必须重写所有的非private方法。

    /**
     * 实现抽象类接口的装饰器对象
     */
    @Slf4j
    public class MappingValidateDecorator  extends AbstractMappingBusinessService{
    
        private AbstractMappingBusinessService abstractMappingBusinessService;
    
        public MappingValidateDecorator(AbstractMappingBusinessService abstractMappingBusinessService) {
            this.abstractMappingBusinessService = abstractMappingBusinessService;
        }
    
        @Override
        public List<ItemAnswerDto> getItemAnswerInfo(PlanInfoDto planInfoDto) {
            return abstractMappingBusinessService.getItemAnswerInfo(planInfoDto);
        }
    
        /**
         * 虽然该装饰器不是处理"数据准备处理器",但是必须原样返回子类的配置(除private方法)。
         * 否则子类将继承抽象类的配置。这可能会导致问题。
         *
         */
        @Override
        protected void prepareHandler(PlanInfoDto planInfoDto) {
            abstractMappingBusinessService.prepareHandler(planInfoDto);
        }
    
        @Override
        protected void validateHandler(PlanInfoDto planInfoDto) {
            abstractMappingBusinessService.validateHandler(planInfoDto);
            log.info("---->校验处理器:MappingValidateDecorator");
        }
    }
    

    (核心)装饰后放入到Spring容器中

    可以灵活的被多个装饰器装饰,动态的扩展功能。

    /**
     * 放入到Spring容器中
     */
    @Configuration
    public class MappingConfig {
        @Bean("mappingDecorator1")
        public MappingBusinessService getV1(MappingBusinessServiceImpl1 mappingBusinessServiceImpl1){
            return new MappingDecorator(mappingBusinessServiceImpl1);
        }
        @Bean("mappingValidateDecorator2")
        public MappingBusinessService getV2(MappingBusinessServiceImpl2 mappingBusinessServiceImpl2){
            return new MappingValidateDecorator(mappingBusinessServiceImpl2);
        }
       
        @Bean("mappingValidateDecorator3")
        public MappingBusinessService getV3(MappingBusinessServiceImpl3 mappingBusinessServiceImpl3){
            return new LogMappingBusinessDecorator(new MappingValidateDecorator(mappingBusinessServiceImpl3));
        }
    }
    

    (核心)路由枚举

    动态的获取Spring对象。
    注:创建的是装饰器对象。

    @Getter
    public enum MappingEnum {
        V1(1, "mappingDecorator1"),
        V2(2, "mappingValidateDecorator2"),
        V3(3, "mappingValidateDecorator3");
    
        private Integer type;
    
        private String clazz;
    
        MappingEnum(Integer type, String clazz) {
            this.type = type;
            this.clazz = clazz;
        }
    
        public static MappingEnum resolve(Integer type) {
            for (MappingEnum mappingEnum : values()) {
                if (mappingEnum.type.equals(type)) {
                    return mappingEnum;
                }
            }
            throw new RuntimeException("类型不存在");
        }
    
        public static MappingBusinessService getBean(Integer type) {
            return SpringUtils.getBean(resolve(type).clazz, MappingBusinessService.class);
        }
    }
    

    借助的工具类。

    @Component
    public class SpringUtils implements ApplicationContextAware {
        private static ApplicationContext applicationContext;
    
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if (SpringUtils.applicationContext == null) {
                SpringUtils.applicationContext = applicationContext;
            }
        }
    
        public static Object getBean(String name) {
            return getApplicationContext().getBean(name);
        }
    
        public static <T> T getBean(Class<T> c) {
            return getApplicationContext().getBean(c);
        }
    
        public static <T> T getBean(String name, Class<T> c) {
            return getApplicationContext().getBean(name, c);
        }
    }
    

    测试

    @RestController
    public class TestMappingController {
    
        @PostMapping("test1")
        public void test(@RequestParam("type") Integer type){
            MappingBusinessService bean = MappingEnum.getBean(type);
            ItemAnswerResp itemAnswerResp = bean.assembleItemAndAnswer(null, null);
        }
    }
    

    效果:

    (LogMappingBusinessDecorator.java:25): 日志装饰器增加可以被撤销的职责
    (MappingValidateDecorator.java:41): ---->校验处理器:MappingValidateDecorator
    (AbstractMappingBusinessService.java:44): AbstractMappingBusinessService的数据准备
    (AbstractSimpleMappingBusinessService.java:20): AbstractSimpleMappingBusinessService的数据准备
    (AbstractMappingBusinessService.java:25): [{"name":"亚瑟"},{"name":"韩信"}]
    

    推荐阅读

    http://m.elecfans.com/article/566111.html

    相关文章

      网友评论

          本文标题:装饰器模式在项目中的实际运用

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