• JAVA【设计模式】装饰器模式


    一、定义

    在这里插入图片描述
    装饰器模式:初看上图感觉装饰器模式有点像俄罗斯套娃、某众汽⻋ ) ,⽽装饰器的核⼼就是再不改原有类的基础上给类新增功能。不改变原有类,可能有的⼩伙伴会想到继承、AOP切⾯
    可以避免继承导致的⼦类过多

    二、示例:

    模拟场景:
    1、例如:公司内部的sso单点登录已经提供好了实现类,已有一套固定的校验体系。此时因为公司业务扩张,需要在原有的校验规则上,新增校验规则,同时还要保证原有的功能不被破坏,这时我们可以考虑使用装饰器模式,扩充原有的单点登录功能。
    在这里插入图片描述

    基础设计

    要想实现拦截的功能,就必须实现此接口HandlerInterceptor

    package com.qf.design.structure.decorate.basic;
    
    public interface HandlerInterceptor {
    
        /**
         * prehandler方法拦截,需要被实现
         */
        boolean preHandler(String request,String response,Object handler);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    父类的基础拦截功能:SsoInterceptor

    package com.qf.design.structure.decorate.basic;
    
    public class SsoInterceptor implements HandlerInterceptor{
        /**
         * 父类的基础拦截功能
         * @param request
         * @param response
         * @param handler
         * @return
         */
        @Override
        public boolean preHandler(String request, String response, Object handler) {
            //模拟获取cookie
            String substring = request.substring(1, 8);
            //是否拦截
            return substring.equals("success");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    传统的编码方式

    重复书写父类实习代码,一旦父类的类变化了,又需要新写子类继承

    package com.qf.design.structure.decorate.tradition;
    
    import com.qf.design.structure.decorate.basic.SsoInterceptor;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class LoginSsoDecoder extends SsoInterceptor {
        public LoginSsoDecoder(){}
    
        private static Map<String,String> authMap=new HashMap<>();
        static {
            authMap.put("huahua", "queryUserInfo");
            authMap.put("doudou", "queryUserInfo");
        }
        @Override
        public boolean preHandler(String request, String response, Object handler) {
            //模拟获取cookie
            String substring = request.substring(1, 8);
            //是否拦截
            boolean success = substring.equals("success");
    
            if (!success) return false;
    
            //自己需要拓展的拦截逻辑
            String userId = request.substring(9);
            String method = authMap.get(userId);
    
            // 模拟方法校验
            return "queryUserInfo".equals(method);
    
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    测试:ApiTest

    package com.qf.design.structure.decorate.tradition;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class ApiTest {
        private static Logger logger= LoggerFactory.getLogger(ApiTest.class);
        public static void main(String[] args) {
            LoginSsoDecoder loginSsoDecoder=new LoginSsoDecoder();
            String request="ssuccessshuahuas";
            boolean result = loginSsoDecoder.preHandler(request, "response", "");
            logger.info("登录校验:"+request+(result?"通过":"失败"));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    装饰器模式设计

    作为中转站,接受传递的子类,并调用子类的preHandler
    被继承的接⼝可以通过构造函数传递其实现类

    package com.qf.design.structure.decorate.design;
    
    import com.qf.design.structure.decorate.basic.HandlerInterceptor;
    
    public abstract class SsoDecoder implements HandlerInterceptor {
        private HandlerInterceptor handlerInterceptor;
    
    
        public SsoDecoder(HandlerInterceptor handlerInterceptor){
            this.handlerInterceptor=handlerInterceptor;
        }
    
        @Override
        public boolean preHandler(String request, String response, Object handler) {
            return handlerInterceptor.preHandler(request,response,handler);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    package com.qf.design.structure.decorate.design;
    
    import com.qf.design.structure.decorate.basic.HandlerInterceptor;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class LoginSsoDecoder extends SsoDecoder{
    
        private static Map<String,String> authMap=new HashMap<>();
        static {
            authMap.put("huahua", "queryUserInfo");
            authMap.put("doudou", "queryUserInfo");
        }
    
        public LoginSsoDecoder(HandlerInterceptor handlerInterceptor){
            super(handlerInterceptor);
        }
    
        @Override
        public boolean preHandler(String request, String response, Object handler) {
            //父类的拦截
            boolean result = super.preHandler(request, response, handler);
            if (!result) return false;
    
            //自己需要拓展的拦截逻辑
            String userId = request.substring(9);
            String method = authMap.get(userId);
            // 模拟方法校验
            return "queryUserInfo".equals(method);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    测试:ApiTest

    package com.qf.design.structure.decorate.design;
    
    import com.qf.design.structure.decorate.basic.SsoInterceptor;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class ApiTest {
        private static Logger logger= LoggerFactory.getLogger(ApiTest.class);
        public static void main(String[] args) {
            LoginSsoDecoder loginSsoDecoder = new LoginSsoDecoder(new SsoInterceptor());
            String request="ssuccessshuahua";
            boolean result = loginSsoDecoder.preHandler(request, "response", "");
            logger.info("登录校验:"+request+(result?"通过":"失败"));
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    UML关系图

    在这里插入图片描述
    总结:
    使⽤装饰器模式满⾜单⼀职责原则,你可以在⾃⼰的装饰类中完成功能逻辑的扩展,⽽不影响主类,同时可以按需在运⾏时添加和删除这部分逻辑。另外装饰器模式与继承⽗类重写⽅法,在某些时候需要需选择,并不⼀定某⼀个就是最好。

    装饰器实现的重点是对抽象类继承接⼝⽅式的使⽤,同时设定被继承的接⼝可以通过构造函数传递其实现类,由此增加扩展性并重写⽅法⾥可以实现此部分⽗类实现的功能。

    假设基础主类发生了重大修改(改了类名或者新写),我们只需要传递最终所需要的主类

  • 相关阅读:
    【python基础4】
    java StringBuilder类、StringBuffer类
    linux系统优化措施汇总-持续更新
    批量多字段唯一性校验
    MySQL数据库索引和事务详解
    【已解决】模糊匹配导致一门课存在多个同名教师
    fat文件系统基础知识
    YAML 语法简介与 C# 操作示例
    ElasticSearch架构设计
    SpringMVC源码--DispatcherServlet 初始化
  • 原文地址:https://blog.csdn.net/cativen/article/details/126181115