前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【设计模式】装饰器模式

【设计模式】装饰器模式

作者头像
Li_XiaoJin
发布2022-06-10 18:16:48
3310
发布2022-06-10 18:16:48
举报
文章被收录于专栏:Lixj's BlogLixj's Blog

定义

装饰器模式就像俄罗斯套娃,它的核心是在不改变原有类的基础上给类新增功能。对于不改变原有类,可能有的人会想到继承、AOP 切面,虽然这些方式都可以实现,但是使用装饰器模式是另外一种更灵活的思路,能够避免继承导致的子类过多问题,也可以避免AOP带来的复杂性问题。

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

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂。

使用场景:

  1. 扩展一个类的功能。
  2. 动态增加功能,动态撤销。

注意事项:可代替继承。

实践

这里模拟一个单点登录权限功能扩充的场景。

代码语言:javascript
复制
public interface HandlerInterceptor {

    boolean preHandle(String request, String response, Object handler);

}

这里模拟的是Spring类HandlerInterceptor,实现接口功能SsoInterceptor模拟的单点登录拦截服务。为了避免引入太多的 Spring 内容,影响对设计模式的理解,这里使用了同名的类和方法,尽可能减少外部的依赖。

模拟单点登录功能

代码语言:javascript
复制
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");
    }
}

使用装饰器模式实现

在装饰类中,有三点需要注意:继承了处理接口,提供了构造函数,覆盖了方法preHandle。以上三点是装饰器模式的核心处理部分,可以替换对子类继承的方式,实现逻辑功能的扩展。

代码语言:javascript
复制
public abstract class SsoDecorator implements HandlerInterceptor {

    private HandlerInterceptor handlerInterceptor;

    private SsoDecorator(){}

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

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

}

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

代码语言:javascript
复制
@Slf4j
public class LoginSsoDecorator extends SsoDecorator {

    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);
        log.info("模拟单点登录方法访问拦截校验:{} {}", userId, method);
        // 模拟方法校验
        return "queryUserInfo".equals(method);
    }
}

在具体的装饰类实现中,继承了装饰类 SsoDecorator,现在可以扩展方法preHandle的功能。在具体的实现代码中可以看到,这里只关心扩展部分的功能,同时不会影响原有类的核心服务,也不会因为使用继承方式而导致出现多余子类,增加了整体的灵活性。

单元测试

代码语言:javascript
复制
public class ApiTest {

    @Test
    public void test_sso() {
        SsoInterceptor ssoInterceptor = new SsoInterceptor();
        String request = "1successhuahua";
        boolean success = ssoInterceptor.preHandle(request, "ewcdqwt40liuiu", "t");
        System.out.println("登录校验:" + request +(success ? " 放行" : " 拦截"));
    }


    @Test
    public void test_LoginSsoDecorator() {
        LoginSsoDecorator ssoDecorator = new LoginSsoDecorator(new SsoInterceptor());
        String request = "1successhuahua";
        boolean success = ssoDecorator.preHandle(request, "ewcdqwt40liuiu", "t");
        System.out.println("登录校验:" + request + (success ? " 放行" : " 拦截"));
    }

}

总结

装饰器主要解决的是直接继承时因功能的不断横向扩展导致子类膨胀的问题,而使用装饰器模式比直接继承更加灵活,同时也不再需要维护子类。

在装饰器模式中,有四点比较重要:

  • 抽象构件角色(Component):定义抽象接口;
  • 具体构件角色(ConcreteComponent):实现抽象接口,可以是一组;
  • 装饰角色(Decorator):定义抽象类并继承接口中的方法,保证一致性;
  • 具体装饰角色(ConcreteDecorator):扩展装饰具体的实现逻辑。

通过以上四种实现装饰器模式,主要核心内容会体现在抽象类的定义和实现方面。

装饰器模式满足单一职责原则,可以在自己的装饰类中完成功能逻辑的扩展而不影响主类,同时可以按需在运行时添加和删除这部分逻辑。

另外,装饰器模式和继承父类重写方法在某些时候要按需选择,并非某个方式就是最好的。装饰器模式实现的重点是对抽象类继承接口方式的使用,同时设定被继承的接口可以通过构造函数传递其实现类,由此增加扩展性,并重写方法中可以通过父类实现的功能。

装饰器模式就像夏天热时穿短裤,冬天冷时穿棉裤,下雨时穿雨衣一样,我们本身并没有被改变,而外形却用不同的服饰表现。生活中的场景比比皆是,如果能够将生活中的例子融入代码实现中,往往会创造出更加优雅的实现方式。

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/设计模式-装饰器模式

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
  • 实践
    • 使用装饰器模式实现
    • 总结
    相关产品与服务
    访问管理
    访问管理(Cloud Access Management,CAM)可以帮助您安全、便捷地管理对腾讯云服务和资源的访问。您可以使用CAM创建子用户、用户组和角色,并通过策略控制其访问范围。CAM支持用户和角色SSO能力,您可以根据具体管理场景针对性设置企业内用户和腾讯云的互通能力。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档