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

一、定义

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

二、示例:

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

基础设计

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

package com.qf.design.structure.decorate.basic;

public interface HandlerInterceptor {

    /**
     * prehandler方法拦截,需要被实现
     */
    boolean preHandler(String request,String response,Object handler);
}

父类的基础拦截功能: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");
    }
}

传统的编码方式

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

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);

    }
}

测试: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?"通过":"失败"));
    }
}

装饰器模式设计

作为中转站,接受传递的子类,并调用子类的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);
    }
}

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);
    }
}

测试: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?"通过":"失败"));
    }
}

UML关系图

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

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

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

posted @ 2022-08-30 22:40  雾托邦  阅读(48)  评论(0编辑  收藏  举报