设计模式十:结构型-装饰器模式

在这里插入图片描述

结构型模式:装饰器模式

装饰器模式

1、装饰器模式:介绍

  • 装饰器模式
    • 在不改变原有类的基础上给类新增功能
  • 装饰器模式:能够避免继承导致的子类过多问题,也可以避免 AOP 带来的复杂性问题。
  • 装饰器模式使用场景
    • new BufferedReader(new FileReader(" "))
    • Java 开发的字节流、字符流和文件流:一层嵌套一层,字节流转字符流等

2、装饰器模式:模拟场景

  • 单点登录场景
    • 以往使用的 SSO 是一个组件化通用的服务,不能在里面添加需要的用户访问验证功能
    • 这时就可以使用装饰器模式扩充原有的单点登录服务,同时也保证原有功能不受破坏,可以继续使用。

3、装饰器模式:场景模拟代码

0、工程结构

lino-design-12.0
|——src
	|——main
		|--java
			|--com.lino.design
    			|--HandlerInterceptor.java
    			|--SsoInterceptor.java

**1、模拟Spring的HandlerInterceptor **

/**
 * @description: 自定义登录拦截接口
 */
public interface HandlerInterceptor {
    /**
     * 登录校验
     *
     * @param request  请求参数
     * @param response 响应参数
     * @param handler  拦截对象
     * @return boolean
     */
    boolean preHandle(String request, String response, Object handler);
}

**2、模拟单点登录功能 **

/**
 * @description: sso登录拦截实现类
 */
public class SsoInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(String request, String response, Object handler) {
        // 模拟获取cookie
        String ticket = request.substring(1, 8);
        // 模拟校验
        return ticket.equals("success");
    }
}

4、装饰器模式:代码实现

  • 装饰器主要解决:直接继承时因功能的不断横向扩展导致子类膨胀的问题
    • 抽象构建角色(Component):定义抽象接口
    • 具体构建角色(ConcreteComponent):实现抽象接口,可以是一组
    • 装饰角色(Decorator):定义抽象类并继承接口中的方法,保证一致性
    • 具体装饰角色(ConcreteDecorator):扩展装饰具体的实现逻辑

0、工程结构

lino-design-11.0
|——src
	|——main
		|--java
			|--com.lino.decorator
    			|--LoginSsoDecorator.java
    			|--SsoDecorator.java
	|——test
    	|--java
    		|--com.lino.test
    			|--Test.java

在这里插入图片描述

  • 重点的类是 SsoDecorator:它表示一个抽象类主要完成了对接口 HandlerInterceptor 的继承
  • 当装饰角色继承接口后,会提供构造函数 SsoDecorator(HandlerInterceptor handlerInterceptor)
    • 入参是继承的接口实现类,可以很方便地扩展出不同的功能组件

1、抽象类装饰角色

  • 装饰类中,有三点需要注意:
    • 继承了处理接口,提供了构造函数,覆盖了方法 preHandler
import com.lino.design.HandlerInterceptor;

/**
 * @description: 抽象类装饰角色
 */
public class SsoDecorator implements HandlerInterceptor {
    /**
     * 自定义登录拦截接口
     */
    private HandlerInterceptor handlerInterceptor;

    public SsoDecorator() {
    }

    public SsoDecorator(HandlerInterceptor handlerInterceptor) {
        this.handlerInterceptor = handlerInterceptor;
    }

    @Override
    public boolean preHandle(String request, String response, Object handler) {
        return handlerInterceptor.preHandle(request, response, handler);
    }
}

2、装饰角色逻辑实现

  • 在具体的装饰类实现中,继承了装饰类 SsoDecorator,现在可以扩展方法 preHandler 的功能。
  • 这里只关心扩展部分的功能,同时不会影响原有类的核心服务,也不会因为使用继承方式而导致出现多余子类,增加了整体的灵活性
import com.lino.design.HandlerInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @description: 装饰角色逻辑实现
 */
public class LoginSsoDecorator extends SsoDecorator {
    /**
     * 日志
     */
    private Logger logger = LoggerFactory.getLogger(LoginSsoDecorator.class);
    /**
     * 用户集合
     */
    private static Map<String, String> authMap = new ConcurrentHashMap<String, String>();

    static {
        authMap.put("huahua", "queryUserInfo");
        authMap.put("doudou", "queryUserInfo");
    }

    public LoginSsoDecorator(HandlerInterceptor handlerInterceptor) {
        super(handlerInterceptor);
    }

    @Override
    public boolean preHandle(String request, String response, Object handler) {
        boolean success = super.preHandle(request, response, handler);
        if (!success) {
            return false;
        }
        String userId = request.substring(8);
        String method = authMap.get(userId);
        logger.info("模拟单点登录方法访问拦截校验:{} {}", userId, method);
        // 模拟方法校验
        return "queryUserInfo".equals(method);
    }
}

3、单元测试

  • 测试了装饰器模式的使用
    • 通过将原有单点登录类 new SsoInterceptor() 传递给装饰器,让装饰器可以执行扩充的功能
    • 同时,传递者和装饰器都可以是多组的
import com.lino.decorator.LoginSsoDecorator;
import com.lino.design.SsoInterceptor;

/**
 * @description: 测试类
 */
public class Test {

    @org.junit.Test
    public void testLoginSsoDecorator() {
        LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(new SsoInterceptor());
        String request = "1successhuahua";
        boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t");
        System.out.println("登录校验:" + request + (success ? " 放行" : " 拦截"));
    }
}
  • 测试结果
14:36:41.328 [main] INFO  com.lino.decorator.LoginSsoDecorator - 模拟单点登录方法访问拦截校验:huahua queryUserInfo
登录校验:1successhuahua 放行

5、装饰器模式:总结

  • 装饰器模式满足单一职责原则
    • 可以在自己的装饰类中完成功能逻辑的扩展而不影响主类。
  • 可以按需在运行时添加和删除这部分逻辑
  • 装饰器模式实现的重点是对抽象类继承接口方式的使用
    • 同时设定被继承的接口可以通过构造函数传递其实现类,由此增加扩展性,并重写方法中可以通过父类实现的功能。

版权声明:本文为qq_35692974原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。