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

news2024/11/13 4:10:40

装饰者模式

一、概述

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

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

装饰者(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子实现进行了功能扩展,加入了缓冲区提高了数据的读写的效率。


《参考资料》

  • 黑马程序员——设计模式
  • 《重学Java设计模式——小傅哥》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/671647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

8年测试老鸟整理,接口自动化测试mock总结,这些你会多少?

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Mock原理/实现机制…

【youcans动手学模型】MobileNet 模型-CIFAR10图像分类

欢迎关注『youcans动手学模型』系列 本专栏内容和资源同步到 GitHub/youcans 【youcans动手学模型】MobileNet 模型-CIFAR10图像分类 1. MobileNet 卷积神经网络模型1.1 模型简介1.2 论文介绍 2. 在 PyTorch 中定义 MobileNet V1 模型类2.1 深度可分离卷积&#xff08;DSC&…

前端vue入门(纯代码)11

【11.全局事件总线(Global Event Bus)】 全局事件总线&#xff1a;实现任意组件间通信 【原理图】 结合上图&#xff0c;假若C组件想要传递数据给A组件&#xff0c;那么&#xff0c;就通过全局事件总线在A组件中绑定【$on】一个自定义事件demo&#xff0c;并界定一个参数来接…

如果我们20年后仍然在讨论Kubernetes,那将是技术上悲哀的时刻

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 Kelsey Hightower Google Cloud首席开发者 引子 在 Kubecon 上&#xff0c;Kelsey Hightower 曾经遇到过一个带有 Kubernetes 纹身的人&#xff0c;这让他开始…

工业相机的镜头如何选择?

相机的镜头如何计算&#xff0c;如果看公式的话&#xff0c;需要知道相机sensor的尺寸&#xff0c;相元的尺寸&#xff0c;计算起来数据也比较复杂&#xff0c;下面教大家一个简单的方法&#xff0c;就是如何借助镜头计算工具来使用。 巴斯勒相机的镜头选型地址 工业镜头选型…

我们该如何提升测试效率?

在大部分研发项目经理心中&#xff0c;进度往往会放在第一位&#xff0c;其次是成本&#xff0c;最后是质量&#xff0c;当然人员队伍最好也要稳定。天下武功&#xff0c;唯快不破&#xff1a;进度 > 成本 > 质量 > 人。 这个说法并不是绝对&#xff0c;今天我们并不是…

【Linux】线程同步条件变量

文章目录 一. 为什么要线程同步二. 条件变量1. 条件变量的使用2. 简单使用 结束语 一. 为什么要线程同步 通过互斥量&#xff0c;也就是加锁解锁&#xff0c;我们可以实现线程互斥&#xff0c;但是当访问的临界区代码较少时&#xff0c;线程执行会出现不停加锁解锁的情况。这样…

uniapp项目中使用vue3开发多端项目实践

目录 1、使用版本说明2、创建项目3、运行项目4、uniapppinia本地缓存插件PiniaPluginUnistorage5、 uni-app vue3 vite ts 项目结构 本项目中使用vue3开发多端项目实践&#xff0c;hbuilderx内置vue3模块&#xff0c;使用了vite4.x构建&#xff0c;编译构建项目的速度比火箭…

dpmsolver 论文核心整理

推导 DPM-Solver1的误差 由正文所述&#xff1a; 利用泰勒展开&#xff1a; B.3式就是换了个元 δ λ − λ s λ t − λ s \delta\frac{\lambda-\lambda_s}{\lambda_t-\lambda_s} δλt​−λs​λ−λs​​&#xff0c;代入论文公式(3.4)的积分项&#xff08;不含系数&…

一套完整的工厂车间现场管理指南,车间主管收藏好了!

车间是企业的基本层&#xff0c;搞好车间现场管理&#xff0c;有利于企业增强竞争力&#xff0c;提高产品质量和员工素质&#xff0c;保证安全生产&#xff0c;而车间班组长是生产线的主要管理者&#xff0c;是直接“当家人”&#xff0c;对生产现场状况了如指掌&#xff0c;对…

0001Java程序设计-SSM校园快递系统的设计与实现

摘 要 21世纪之后&#xff0c;全球信息化逐渐加快&#xff0c;尤其表现在近几年来电商行业的飞速发展&#xff0c;人们足不出户就可以买到自己想要的商品&#xff0c;尤其是青年大学生&#xff0c;追求新颖&#xff0c;更加乐忠于网络购物。网络购物的增加&#xff0c;就导致物…

【二】python爬虫进行AES解密遇到的问题

1、TypeError: Object type <class ‘str’> cannot be passed to C code 报错如下&#xff1a; File "C:\Python311\Lib\site-packages\Crypto\Util\_raw_api.py", line 143, in c_uint8_ptrraise TypeError("Object type %s cannot be passed to C cod…

【使用Spring Cloud Gateway构建微服务网关】—— 每天一点小知识

&#x1f4a7; 使用 S p r i n g C l o u d G a t e w a y 构建微服务网关 \color{#FF1493}{使用Spring Cloud Gateway构建微服务网关} 使用SpringCloudGateway构建微服务网关&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主…

54 KVM工具使用指南-vmtop使用指南

文章目录 54 KVM工具使用指南-vmtop使用指南54.1 概述54.1.1 多架构支持54.1.2 显示项说明54.1.2.1 AArch64和x86_64架构公共显示项54.1.2.2 仅AArch64架构的显示项54.1.2.3 仅x86_64架构的显示项 54.2 使用方法54.2.1 语法格式54.2.2 选项说明54.2.3 快捷键 54.3 示例 54 KVM工…

MSP432学习笔记10:串口接收字符串命令并执行任务

今日终于得以继续我的MSP432电赛速通之路&#xff1a; 串口通信是单片机需要学习深入的一个很重要的板块&#xff0c;通过串口&#xff0c;我们可以实现许多数据收发与调试工作&#xff0c;可谓是非常方便快捷。 今日就跟随我的脚步&#xff0c;逐步扎实地学习如何编程MSP432…

2023-06-21:redis中什么是BigKey?该如何解决?

2023-06-21&#xff1a;redis中什么是BigKey&#xff1f;该如何解决&#xff1f; 答案2023-06-21&#xff1a; 什么是bigkey bigkey是指存储在Key-Value数据库中的键对应的值所占用的内存空间较大。举个例子&#xff0c;如果值是字符串类型&#xff0c;它可以达到最大512MB的…

堆体系结构概述

1、逻辑概述 2、堆会出现的异常 3、物理上划分 &#xff08;1&#xff09;新生区 新生区是类的诞生、成长、消亡的区域&#xff0c;一个类在这里产生&#xff0c;应用&#xff0c;最后被垃圾回收器收集&#xff0c;结束生命。新生区又分为两部分&#xff1a; 伊甸区&#xff0…

Goby 漏洞发布|WordPress User Post Gallery 插件 upg_datatable 远程代码执行漏洞(CVE-2022-4060)

漏洞名称&#xff1a;WordPress User Post Gallery 插件 upg_datatable 远程代码执行漏洞&#xff08;CVE-2022-4060&#xff09; English Name&#xff1a;WordPress plugins User Post Gallery upg_datatable RCE Vulnerability (CVE-2022-4060) CVSS core: 9.8 影响资产数…

Observability:如何把 Elastic Agent 采集的数据输入到 Logstash 并最终写入到 Elasticsearch

在之前的文章 “安装独立的 Elastic Agents 并采集数据 - Elastic Stack 8.0”&#xff0c;我们详述了如何使用 No Fleet Server 来把数据写入到 Elasticsearch 中。在今天的文章中&#xff0c;我们来详述如下使用 Elastic Agents 在独立&#xff08;standalone&#xff09;模式…

Gradio Blocks:自定义交互式Web应用和演示

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…