设计模式-装饰器模式(结构型)与责任链模式(行为型)对比,以及链式设计

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 1.装饰器模式
    • 1.1概念
    • 1.2作用
    • 1.3应用场景
    • 1.4特点
    • 1.5类与对象关系
    • 1.6实现
  • 2责任链模式
    • 2.1概念
    • 2.2作用
    • 2.3应用场景
    • 2.4特点
    • 2.5类与对象关系
    • 2.6实现
  • 3.对比
  • 总结


前言

装饰器模式和设计模式同为GoF23中设计模式之一,两者在结构上有相似之处,本文章用来学习两个设计模式,并进行对比。


1.装饰器模式

1.1概念

如果我们想要为一个已经写好的类增加新功能,在不修改该类源码的情况下,我们有以下选择:

  • 创建该类的子类,并用该子类调用父类方法,并额外添加其他功能
  • 创建一个新的类,引用已有类的对象,调用原有方法并添加其他功能

这里第二种实现思路就是我们现在说的装饰器模式。

1.2作用

为一个已有的类增加新的功能。

1.3应用场景

  • 需要动态地给对象添加职责时:当你需要给某个对象添加职责,但又不想修改其类定义时,可以使用装饰器模式。
  • 需要灵活组合多个职责时:当你有多个职责需要组合,并且这些职责的排列组合可能会变化时,装饰器模式是一个很好的选择。
  • 需要保持类的单一职责原则时:当你想保持类的单一职责原则,但又需要给类添加额外的职责时,可以使用装饰器模式将这些职责分离到装饰器

1.4特点

  • 动态扩展:装饰器模式能够在运行时动态地给对象添加职责,而无需修改类的定义。
  • 灵活性:通过组合的方式而不是继承来扩展功能,这使得装饰器模式比继承更加灵活。
  • 遵循开闭原则:装饰器模式可以在不修改现有代码的情况下添加新的功能,符合开闭原则(对扩展开放,对修改关闭)。
  • 装饰器与被装饰对象拥有相同的接口:这使得装饰器可以透明地替代被装饰对象

1.5类与对象关系

在这里插入图片描述

  • 组件接口:对应上图Component,用来规定被装饰对象和装饰器应该有哪些功能(或者说原组件中哪些功能是可以装饰的)
  • 组件类:对应上图ConcreteComponent,是被装饰对象
  • 抽象装饰器:对应上图Decorator,是一个接口,因为我们会有多个不同的具体装饰器,所以需要使用一个抽象装饰器接口来指定具体装饰器应该有哪些功能
  • 具体装饰器:是我们真正的额外功能编写的地方,因为实现了抽象装饰器所以拥有与被装饰对象相同但更强大的功能,可以在使用时进行替换。

1.6实现

// 定义一个接口,规定哪些方法可以被装饰
interface Component {
    void operation();
}
 
// 具体组件类,实现了Component接口
class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent operation");
    }
}
 
// 抽象装饰器类,持有一个Component对象,并实现了Component接口
abstract class Decorator implements Component {
  // 该对象存储原对象或者被其他装饰器装饰过的对象
  // 因为可以是其他装饰器装饰过的对象,所以才实现装饰器的叠加,是动态添加功能的关键
    protected Component component;
 
    public Decorator(Component component) {
        this.component = component;
    }
 
    @Override
    public void operation() {
        component.operation();
    }
}
 
// 具体装饰器类A,增加了额外的行为
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
 
    @Override
    public void operation() {
        super.operation();
        addedBehavior();
    }
 
    private void addedBehavior() {
        System.out.println("ConcreteDecoratorA added behavior");
    }
}
 
// 具体装饰器类B,增加了额外的行为
class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }
 
    @Override
    public void operation() {
        addedBehavior();
        super.operation();
    }
 
    private void addedBehavior() {
        System.out.println("ConcreteDecoratorB added behavior");
    }
}
 
// 客户端代码
public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
 
        // 使用装饰器A装饰
        Component decoratorA = new ConcreteDecoratorA(component);
        // 使用装饰器B装饰装饰器A
        Component decoratorB = new ConcreteDecoratorB(decoratorA);
 
        // 执行操作,将展示所有组件和装饰器的行为
        decoratorB.operation();
    }
}

2责任链模式

2.1概念

责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行传递。每个处理者可以对请求进行处理,或者将请求传递给链中的下一个处理者。这使得你可以在不明确具体接收者的情况下,向多个对象发送请求。

2.2作用

  • 解耦请求与处理:请求者只要向链头发送一次请求,而不用关心具体由谁处理。
  • 可以动态管理处理类:可以按需添加或删除处理类。

2.3应用场景

  • 多个对象有机会处理请求:当请求可以在多个对象之间传递,并且每个对象都有可能处理它时。
  • 请求处理顺序可变:当请求的处理顺序不固定,或者你想在不修改代码的情况下改变处理顺序时。
  • 解耦请求发送者和处理者:当你想解耦请求发送者和处理者之间的依赖关系时。

2.4特点

  • 链式传递:请求在多个处理者之间传递,直到有一个处理者处理它或链结束。
  • 解耦请求发送者和接收者:发送者不需要知道哪个具体的处理者会处理请求,它只需要将请求发送到链的头部即可。
  • 增强灵活性:你可以通过动态地添加或删除处理者来改变链的结构,从而改变请求的处理流程。

2.5类与对象关系

在这里插入图片描述

责任链模式中我们有以下角色:

  • 抽象处理者(Handler)角色:声明“处理”方法,以及一个“设置下一处理器”的方法
  • 具体处理者(Concrete Handler)角色:实现了抽象处理者接口,并包含处理请求的逻辑。如果它不能处理请求,它会将请求传递给链中的下一个处理者。

2.6实现

// 抽象处理者接口
abstract class Handler {
    protected Handler nextHandler;
 
    // 设置下一个处理者
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }
 
    // 处理请求的方法,由具体处理者实现
    public abstract void handleRequest(String request);
}


// 具体处理者类A
class ConcreteHandlerA extends Handler {
    @Override
    public void handleRequest(String request) {
        if ("A".equals(request)) {
            System.out.println("ConcreteHandlerA handled request: " + request);
        } else {
            if (nextHandler != null) {
                nextHandler.handleRequest(request);
            }
        }
    }
}


// 具体处理者类B
class ConcreteHandlerB extends Handler {
    @Override
    public void handleRequest(String request) {
        if ("B".equals(request)) {
            System.out.println("ConcreteHandlerB handled request: " + request);
        } else {
            if (nextHandler != null) {
                nextHandler.handleRequest(request);
            }
        }
    }
}


// 客户端代码
public class ChainOfResponsibilityDemo {
    public static void main(String[] args) {
        // 创建处理者对象
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
 
        // 构建处理者链
        handlerA.setNextHandler(handlerB);
 
        // 创建并发送请求
        String[] requests = {"A", "B", "C"};
 
        for (String request : requests) {
            handlerA.handleRequest(request); // 请求从handlerA开始传递
        }
    }
}

3.对比

  1. 首先,链式设计最重要的一点是——一个节点中要存储相邻节点的信息,这一点在上述两种设计模式中都有体现。这里要先清楚各自具体存储的是什么。
  • 装饰器模式存储的是原组件或被修饰过的组件,这说明在该种模式下各个装饰器的作用是可以叠加的
  • 责任链模式存储的是下一个处理节点,这里各个处理器效果并不会叠加
  1. 其次,各个节点应该有同样的任务。这两种模式中不论是各个装饰器,还是各个处理器,其实都有同样的任务。但是两个模式在具体实现时有区别,这也是装饰器模式可叠加而责任链模式不可叠加的原因。
  • 装饰器中的方法逻辑是——上一节点处理逻辑"及"本节点处理逻辑
  • 责任链中的方法逻辑是——本节点处理逻辑"或"下节点处理逻辑

总结

本文章比较了装饰器模式和责任链模式,因为两者在结构上十分相似都使用了链式设计,所以容易混淆,这里需要重点理解两者在处理方法中的实现逻辑的不同,装饰器是"且",责任链是"或"。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TesseractOCR-GUI:基于WPF/C#构建TesseractOCR简单易用的用户界面

前言 前篇文章使用Tesseract进行图片文字识别介绍了如何安装TesseractOCR与TesseractOCR的命令行使用。但在日常使用过程中,命令行使用还是不太方便的,因此今天介绍一下如何使用WPF/C#构建TesseractOCR简单易用的用户界面。 普通用户使用 参照上一篇教…

解决 IntelliJ IDEA 启动错误:插件冲突处理

引言 在使用 IntelliJ IDEA 进行开发时,我们可能会遇到各种启动错误。本文将详细介绍一种常见的错误:插件冲突,并提供解决方案。 错误背景 最近,有用户在启动 IntelliJ IDEA 时遇到了一个错误,提示信息为&#xff1a…

多线程的知识总结(8):用 thread 类 或全局 async (...) 函数,创建新线程时,谁才是在新线程里第一个被执行的函数

(40)用 thread 类 或全局 async (…) 函数,创建新线程时,谁才是在新线程里第一个被执行的函数? 弄清楚这个问题,有利于推测和理解线程中代码的执行流程。根据 thread 类 和 async (…&#xff0…

ChatGPT 4:解锁AI文案、绘画与视频创作新纪元

文章目录 AI文案:激发文字的魅力,重塑营销与传播AI绘画:解锁艺术的无限可能,激发创意灵感AI视频:重塑视频创作流程,提升制作效率GPTs:构建个性化AI应用,赋能各行各业《ChatGPT 4 应用…

【pyspark学习从入门到精通23】机器学习库_6

目录 分割连续变量 标准化连续变量 分类 分割连续变量 我们经常处理高度非线性的连续特征,而且只用一个系数很难拟合到我们的模型中。 在这种情况下,可能很难只通过一个系数来解释这样一个特征与目标之间的关系。有时,将值划分到离散的桶中…

linux 进程间通信:匿名管道pipe()

进程间内存独立且相互不可见,进程间通信需要特殊方法 匿名管道pipe() /* Create a one-way communication channel (pipe). If successful, two file descriptors are stored in PIPEDES; bytes written on PIPEDES[1] can be read from PIPEDES[0]. Retu…

哈默纳科Harmonic谐波减速机机器人精准高效动力传递的核心力量

在当今科技飞速发展的时代,机器人技术正以惊人的速度改变着我们的生产与生活方式。而在机器人的精密机械结构中,哈默纳科 Harmonic 谐波减速机扮演着不可或缺的角色,成为机器人精准高效动力传递的关键所在。 1.高精度与灵活性:哈默…

Codigger SIDE之Helix编辑器

在Codigger的多维世界中,Helix编辑器以其卓越的性能和灵活性,成为开发者手中的利剑。基于Rust构建,Helix不仅继承了Vim编辑器的经典特性,更以其现代化的功能,重新定义了代码编辑的边界。 模式切换的艺术 Helix的模式切…

Scala的正则表达式二

验证用户名是否合法 规则 1.长度在6-12之间 2.不能数字开头 3.只能包含数字,大小写字母,下划线def main(args: Array[String]): Unit {val name1 "1admin"//不合法,是数字开头val name2 "admin123"//合法val name3 &quo…

C++ 运算符重载 (备查)

基础 运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。 运算符重载也可以发生函数重载。 语法: void operator(); //代表了被重载的运算符。函数的参数个数取决于两个因素。1)运算符是一元(一…

zerotier实现内网穿透(访问内网服务器)

moo 内网穿透工具 实用工具:zerotier 目录 内网穿透工具 Windows下zerotier安装 ubuntu系统下的zerotier安装 使用moon加速 Windows下zerotier安装 有了网络之后,会给你一个网络id,这个网络id是非常重要的,其它设备要加入…

【C++】刷题强训(day14)--乒乓球匡、组队竞赛、删除相邻数字的最大分数

目录 1、乒乓球匡 1.1题目 1.2 思路 1.3 代码实现 2、组队竞赛 2.1 题目 2.2 思路 2.3 代码实现 3、删除相邻数字的最大分数 3.2 思路 3.3 代码实现 刷题汇总&#xff1a;传送门&#xff01; 1、乒乓球匡 1.1题目 1.2 思路 这道题注意一下示例&#xff0c;<br…

Windows安装elasticsearch、Kibana以及IK分词器

一、下载 1.下载elasticsearch 访问官网Download Elasticsearch | Elastic&#xff0c;下载elasticsearch 2.下载 Kibana 访问Download Kibana Free | Get Started Now | Elastic &#xff0c;下载 Kibana 3. IK分词器下载 访问Gitee 极速下载/elasticsearch-analysis-ik选…

STM32输入捕获详解

目录 一、引言 二、输入捕获原理 三、寄存器介绍 四、配置步骤 1.开启时钟 2.GPIO 初始化 3.初始化定时器 4.配置输入捕获模式 5.使能捕获和更新中断 6.设置中断分组并编写中断服务函数 7.使能定时器 五、程序示例 六、总结 一、引言 在嵌入式系统开发中&#xff0…

聚类及Python下实现 K-means 算法

聚类 聚类是无监督学习中的一种重要方法&#xff0c;旨在将数据集中相似的数据对象划分到同一个簇中&#xff0c;使得不同簇之间的数据对象差异尽可能大。在大数据环境下&#xff0c;聚类可以帮助挖掘数据中的隐藏结构和模式&#xff0c;应用场景十分广泛&#xff0c;比如在客…

开源分布式系统追踪-01-Zipkin-01-入门介绍

分布式跟踪系列 CAT cat monitor 分布式监控 CAT-是什么&#xff1f; cat monitor-02-分布式监控 CAT埋点 cat monitor-03-深度剖析开源分布式监控CAT cat monitor-04-cat 服务端部署实战 cat monitor-05-cat 客户端集成实战 cat monitor-06-cat 消息存储 skywalking …

解决Jmeter HTTP Cookie管理器cookie不生效

解决Jmeter HTTP Cookie管理器cookie不生效问题 解决Jmeter HTTP Cookie管理器cookie不生效问题1、设置Jmeter HTTP Cookie管理器cookie后&#xff0c;发起的请求显示[no cookies]jmeter问题复现&#xff1a;这里同样使用postman进行重试&#xff0c;发现是可以正常获取数据的&…

【6】数据分析检测(DataFrame 1)

学习目标3 昨天&#xff0c;我们学习了Series。 而Pandas的另一种数据类型&#xff1a;DataFrame&#xff0c;在许多特性上和Series有相似之处。 今天&#xff0c;我们将学习DataFrame的相关知识&#xff1a; 1. DataFrame的概念 2. 构造一个DataFrame 3. DataFrame的常用…

LeetCode 热题 100_环形链表 II(26_142_中等_C++)(单链表;哈希表;快慢指针)

LeetCode 热题 100_环形链表 II&#xff08;26_142&#xff09; 题目描述&#xff1a;输入输出样例&#xff1a;题解&#xff1a;解题思路&#xff1a;代码实现&#xff08;思路一&#xff08;哈希表&#xff09;&#xff09;&#xff1a;代码实现&#xff08;思路二&#xff0…

如何通过看板进行跨境电商的圣诞商品数据分析与优化选品流程?

引言 随着圣诞季的临近&#xff0c;跨境电商迎来了重要的销售时机。选品工作对于跨境电商的成功至关重要&#xff0c;直接关系到销售业绩和利润。本文结合相关网页信息&#xff0c;深入探讨跨境电商在圣诞期间如何利用信息整合工具展开选品工作&#xff0c;并优化选品流程。同…