Java设计模式——装饰者模式

装饰者模式

一、概述

装饰者模式(装饰器模式)是一种结构型模式

定义: 在不改变现有对象结构的情况下,动态地给该对象增加一些额外职责(功能)的模式。

装饰者(Decorator)模式中的角色:

  • 抽象构件(Component)角色: 定义一个抽象接口准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色: 实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色: 继承或实现抽象构件,聚合抽象构件,通过子类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色: 实现抽象装饰的相关方法,扩展具体构件的职责。

二、案例场景模拟

场景: 在业务发展初期SSO单点登录只需要进行用户登录状态验证即可,但随着业务发展团队成员的扩充,比如专门的运营人员、营销人员、数据人员,不同的人员对数据的操作不同。为了保证数据的安全性,需要给不同的角色分配相应的权限,当用户访问自身权限外的业务数据时进行拦截。

在原有SSO单点登录不受破坏的前提下,进行功能扩展。

1. 继承模拟实现

1.1 模拟Spring中的HandlerInterceptor


public interface HandlerInterceptor {
    // 登录校验
    boolean preHandle(String request, String response, Object handler);
}

1.2 模拟单点登录

public class SsoInterceptor implements HandlerInterceptor{
    @Override
    public boolean preHandle(String request, String response, Object handler) {
        // 模拟获取cookie
        String ticket = request.substring(1,3);

        // 校验
        return "ok".equals(ticket);

    }
}

1.3 继承后重写方法添加模拟方法拦截

public class LoginSsoDecorator extends SsoInterceptor {
    private static Map<String, String> authMap = new ConcurrentHashMap<>();

    static {
        authMap.put("liming", "findInfo");
        authMap.put("xiaohua", "findInfo");
    }

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

        if (!success) return false;
        String userId = request.substring(3);

        String method = authMap.get(userId);

        return "findInfo".equals(method);
    }
}

1.4 测试类:

public class Client {
    public static void main(String[] args) {
        LoginSsoDecorator ssoDecorator = new LoginSsoDecorator();
        String request = "1okliming";
        boolean success = ssoDecorator.preHandle(request, "200", "handler");
        System.out.println("登录校验:" + request + (success ? " 放行": " 拦截"));

    }
}

测试结果:
在这里插入图片描述

2. 装饰者模式重构

2.1 抽象构件角色 HandlerInterceptor

public interface HandlerInterceptor {
    // 登录校验
    boolean preHandle(String request, String response, Object handler);
}
 

2.2 具体构件角色 SsoInterceptor

public class SsoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(String request, String response, Object handler) {
        // 模拟获取cookie
        String ticket = request.substring(1,3);

        // 校验
        return "ok".equals(ticket);

    }
}

2.3 抽象装饰类SsoDecorator

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

    }
}

抽象装饰者角色继承了prehandle接口,聚合抽象构件handlerInterceptor

2.4 具体装饰类LoginSsoDecorator

public class LoginSsoDecorator extends SsoDecorator {
    private static Map<String, String> authMap = new ConcurrentHashMap<>();

    static {
        authMap.put("liming", "findInfo");
        authMap.put("xiaohua", "findInfo");
    }

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

    @Override
    public boolean preHandle(String request, String response, Object handler) {
        // 获取cookie 模拟登录校验

        boolean success = super.preHandle(request, response, handler);

        if (!success) return false;
        String userId = request.substring(3);

        String method = authMap.get(userId);
        System.out.println("模拟单点登录方法拦截:" + userId + " " + method);

        return "findInfo".equals(method);
    }
}

在具体的装饰类​*LoginSsoDecorator中继承了抽象装饰类SsoDecorator,而SsoDecorator又实现并聚合了HandlerInterceptor,因此LoginSsoDecorator可以对接口perHandle进行扩展并且不会影响原有类的实现,也不会因为继承导致多余子类,增加了整体的灵活性。

2.5 测试类:

public class Client {
    public static void main(String[] args) {
        LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(new SsoInterceptor());
        String request = "1okliming";
        boolean success = ssoDecorator.preHandle(request, "200", "handler");
        System.out.println("登录校验:" + request + (success ? " 放行": " 拦截"));

    }


}

将单点登录类SsoInterceptor 传递给装饰器,装饰器可以进行功能扩展

测试结果:
在这里插入图片描述


三、优势与适用场景

1. 优势:

  • 装饰者模式可以带来比继承更加灵活性的扩展,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化结果。装饰者模式遵循开闭原则,动态的附加责任。
  • 装饰类和被装饰类相互独立,可以分别扩展互不影响。

2. 使用场景:

  • 当不能采用继承的方式对系统进行扩充或者采用继承造成子类过多不利于系统扩展和维护时。
  • 在不影响接口现有功能下进行动态扩展。

例子: 比如spring框架中的HandlerInterceptor拦截器、JDK中的IO流BufferedInputStreamBufferedWriter是对InputStreamWriter子实现进行了功能扩展,加入了缓冲区提高了数据的读写的效率。


《参考资料》

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

〖雪月清〗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值