链式设计模式——装饰模式和职责链模式

news2025/3/1 21:13:07

一、装饰模式

1、概述

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

  • ConcreteComponent :是定义了一个具体的对象,可以给这个对象添加一些职责;
  • Decorator :装饰抽象类,继承了Component,从外部类来扩展Component类的功能,但对于Component来说,无需知道Decorator的存在的;
  • ConcerteDecorator :就是具体的装饰对象,起到给Component添加职责的功能;
2、代码演示模块: 

我们这里就用给一个对象穿衣服的例子,来说明装饰模式:
(1)Person类(Component)

public class Person {
    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    public void show() {
        System.out.println("装扮的"+ name);
    }
}

(2)饰类(Decorator)

public abstract class Finery extends Person {
    //人对象作为属性
    private Person component;
    
    //get和set方法
    public Person getComponent() {
        return component;
    }
    public void setComponent(Person component) {
        this.component = component;
    }

	//重写父类的某个功能
    public void show(){
        if (component != null){
            component.show();
        }
    }
}

(3)具体服饰类(ConcreteDecorator)

public class Suit extends Finery {
    public void show() {
        System.out.print("T恤");
        super.show();
    }
}

public class TShirts extends Finery {
    public void show(){
        System.out.print("运动裤");
        super.show();
    }
}

.
.
.

public class GymShoes extends Finery {
    public void show() {
        System.out.print("球鞋");
        super.show();
    }
}

(4)客户端代码:

public class test {
    public static void main(String[] args) {
        Person person = new Person("某某");

        System.out.print("第一种装扮:");

        Finery ts = new TShirts();
        Finery bt = new BigTrouser();
        Finery gs = new GymShoes();

        ts.setComponent(person);
        bt.setComponent(ts);
        gs.setComponent(bt);
        gs.show();

        System.out.print("第二种装扮:");

        Finery ne = new Necktie();
        Finery su = new Suit();
        Finery ls = new LeatherShoes();

        ne.setComponent(person);
        su.setComponent(ne);
        ls.setComponent(su);
        ls.show();

    }
}

运行结果:
第一种装扮:球鞋  垮裤  大T恤  装扮的某某
第二种装扮:皮鞋  西装  领带  装扮的某某
3、优点

(1)增强功能的灵活性:

       装饰模式可以在不改变原有对象结构的基础上,动态地给对象添加新的功能。例如,在一个咖啡店的点单系统中,有一个基础的咖啡类Coffee,它有一个方法cost()用于计算咖啡的价格。通过装饰模式,可以创建诸如MilkDecorator(牛奶装饰器)、SugarDecorator(糖装饰器)等装饰类。这样,用户可以根据自己的喜好选择添加牛奶或糖来装饰咖啡,而不需要改变Coffee类本身的结构。如果后续还想添加新的配料,如焦糖、香草等,只需要创建新的装饰类即可。

 (2)实现多层装饰组合

        可以对一个对象进行多层装饰,以实现复杂的功能组合。比如,对于上面的咖啡示例,可以先使用MilkDecorator装饰Coffee对象,然后再使用SugarDecorator进行装饰。这样就可以得到一杯加了牛奶和糖的咖啡。每一层装饰都可以独立地添加自己的功能,并且这些功能会按照装饰的顺序依次叠加。这种组合方式非常灵活,可以满足各种复杂的业务需求。

(3)符合开闭原则

         该模式对扩展开放,对修改关闭。当需要为对象添加新的功能时,不需要修改原有的类,而是通过创建新的装饰类来实现。这使得系统具有更好的可维护性和可扩展性。以图形绘制系统为例,有一个基本的图形类Shape,它有一个draw()方法用于绘制图形。如果要为图形添加新的绘制效果,如阴影、渐变等,可以通过创建ShadowDecoratorGradientDecorator等装饰类来实现,而不用修改Shape类的代码。

4、缺点

        增强了系统的复杂度, 随着装饰类的增多,系统的复杂度会逐渐增加。因为每个装饰类都要了解被装饰对象的接口,而且装饰类之间可能会相互嵌套,这使得代码的理解和调试变得困难。例如,在一个大型的电商系统中,对商品价格计算功能进行装饰,可能会有折扣装饰、运费装饰、税费装饰等多种装饰类。如果这些装饰类的逻辑比较复杂,而且相互嵌套,就会给开发人员理解和维护代码带来很大的挑战。

5、总结

(1)装饰模式是为已有的功能动态的添加更多的功能的一种方式,属于开闭原则,对扩展开放、修改关闭,降低代码的耦合性,符合代码的设计原子低耦合高内聚,减少了代码的冗余和复杂度,更加灵活的使用每个模块。
(2)那什么时候适合去使用它呢?
     正常不使用装饰模式下: 当系统需要新功能的时候,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为,这么做的问题主要是在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅只是为了满足一些只在特定情况下才会执行的特殊行为的需要。
(3)在使用装饰模式下: 它是把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选则的按顺序使用装饰功能包装对象。

二、职责链模式

1、概述

        使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。


Handler :抽象处理请求类:将自身设为自己的属性,再定义一个解决请求的抽象方法
ConcreteHandler : 具体处理请求类,继承Handler抽象类,重写解决请求的方法。每一个的解决请求的方法体可以相互包含,也可以形成互补的方法。可访问它的后继者,如果可处理该请求,就处理。否则就将该请求转发给后继者;

2、代码演示模块

我们处理一组数据,演示职责模式。

(1)Handler类,定义一个处理请求的接口

abstract class Handler {
    protected Handler successor;
    public void setSuccessor(Handler successor){
        //设置继承者
        this.successor = successor;
    };
        //处理请求的抽象方法
    public abstract void handleRequest(int request);
}

(2)ConcreteHandler1,当请求数在0-10之间则有权处理,否则转到下一位



public class ConcreteHandler1 extends Handler{
    public void handleRequest(int request){
        //0-10处理请求
        if(request>=0&&request<=10){
            System.out.println("ConcreteHandler1 handle request "+request);
        }else{
            if(successor!=null){
            //转移到下一位
                successor.handleRequest(request);
            }
        }
    }
}

 (3)ConcreteHandler2,当请求数在10-20之间则有权处理,否则转到下一位


public class ConcreteHandler2 extends Handler{
    public void handleRequest(int request)
    {
        if(request >= 10 && request < 20)
        {
            System.out.println("ConcreteHandler2 处理请求:" + request);
        }
        else if(successor != null)
        {
            successor.handleRequest(request);
        }
    }
}

(4)ConcreteHandler3,请求20-30之间有权处理,否则转到下一位


public class ConcreteHandler3 extends Handler{
    public void handleRequest(int request)
    {
        if(request>=20&&request<30)
        {
            System.out.println("---由第三个处理者处理---");
        }
        else
        {
            if(successor!=null)
            {
                successor.handleRequest(request);
            }
        }
    }
}

(5) 客户端代码


public class Start {
    public static void main(String[] args) {
        // 创建一个请求
        int request = 5;
        // 创建三个处理者
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        Handler handler3 = new ConcreteHandler3();
        // 设置处理者链
        handler1.setSuccessor(handler2);
        handler2.setSuccessor(handler3);
        // 处理请求
       int [] result ={2,5,14,22,18,3,27,20};
       for (int i=0;i<result.length;i++){
           handler1.handleRequest(result[i]);
       }
    }
}
3、优点

(1)降低了发送者和接收者之间的耦合

       在责任链模式中,请求的发送者不需要知道具体是哪个接收者来处理请求。它只需要将请求发送到责任链的起始端即可。例如,在一个投诉处理系统中,用户提交投诉后,投诉请求会沿着预先设定的责任链(可能是客服代表 - 客服主管 - 部门经理)传递,用户不需要了解具体是哪个环节会处理他的投诉,这样就降低了发送者和接收者之间的耦合度。

(2)增强系统的灵活性和可扩展性

新的处理者可以很容易地添加到责任链中。

4、缺点

(1)部分请求可能未被处理

        如果责任链没有正确配置,或者没有合适的处理者能够处理某个请求,这个请求可能会一直传递到责任链的末尾而得不到处理。比如,在一个数据验证系统中,如果没有对所有可能的数据类型都配置相应的验证处理者,那么一些特殊类型的数据可能就无法得到验证,从而导致数据错误进入后续流程。

(2)调试困难

        由于请求在责任链中可能经过多个处理者,当出现问题时,确定是哪个处理者导致的问题可能会比较复杂。例如,在一个复杂的工作流审批系统中,如果一个审批请求出现异常,可能需要逐一检查责任链中的每个审批者的处理逻辑和状态,才能找到问题所在。

 5、总结

        责任链模式提供了一种灵活的方式来处理请求,使得多个对象可以有机会参与到请求的处理过程中。通过解耦请求发送者和接收者,它增强了系统的可维护性和可扩展性。然而,使用这种模式也需要注意其潜在的缺点,如调试困难、可能出现请求未被处理的情况以及性能问题。

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

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

相关文章

JavaEE多线程案例之阻塞队列

上文我们了解了多线程案例中的单例模式&#xff0c;此文我们来探讨多线程案例之阻塞队列吧 1. 阻塞队列是什么&#xff1f; 阻塞队列是⼀种特殊的队列.也遵守"先进先出"的原则. 阻塞队列是⼀种线程安全的数据结构,并且具有以下特性: 当队列满的时候,继续⼊队列就会…

【Linux】VMware 安装 Ubuntu18.04.2

ISO镜像安装步骤 选择语言 English 选择键盘布局 English 选择系统 Ubuntu 虚拟机网卡地址&#xff0c;默认即可 代理地址&#xff0c;默认空即可 镜像地址&#xff0c;修改成阿里云地址 选择第二项&#xff0c;LVM 磁盘扩容技术 第一块硬盘名sda&#xff0c;默认…

Unity游戏实战

很小的时候在键盘机上玩过一个游戏叫寻秦&#xff0c;最近看有大佬把他的安卓版做出来了&#xff0c;打开封面就是Unity&#xff0c;想自己也尝试一下。

R语言的数据结构-向量

【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言编程_夏天又到了的博客-CSDN博客 在R语言中&#xff0c;数据结构是非常关键的部分&#xff0c;它提…

CTF misc 流量分析特训

以下题目来源于西电的靶场&#xff0c;从NewStar CTF开始 wireshark_checkin 进来看一下http流&#xff0c;结果真的找到flag了&#xff08;感觉有点狗运&#xff09;&#xff0c;第一道流量分析题就这么奇奇妙妙的解出来了 wireshark_secret 根据提示猜测flag可能在图片里&…

React v19稳定版发布12.5

&#x1f916; 作者简介&#xff1a;水煮白菜王 &#xff08;juejin/csdn同名&#xff09;&#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧✍。 感谢支持&a…

【JVM】JVM基础教程(三)

上一章&#xff1a;【JVM】JVM基础教程&#xff08;二&#xff09;-CSDN博客 目录 运行时数据区 应用场景 程序计数器 程序计数器在运行时会出现内存溢出吗&#xff1f; 栈 IDEA的debug工具查看栈帧的内容 栈帧的组成 局部变量表 关于 this 的内存存储 操作数栈 帧…

Postman Sandbox 项目教程

Postman Sandbox 项目教程 postman-sandbox Sandbox for Postman Scripts to run in Node.js or browser 项目地址: https://gitcode.com/gh_mirrors/po/postman-sandbox 1. 项目介绍 Postman Sandbox 是一个用于在 Node.js 或浏览器中执行 Postman 脚本的沙盒环境。它…

Maven、mybatis框架

一、Maven介绍 1.概念&#xff1a; Maven项目对象模型(POM)&#xff0c;可以通过一小段描述信息来管理项目的构建&#xff0c;报告和文档的项目管理工具软件。 2.为啥使用maven: 之前项目中需要引入大量的jar包。这些jar从网上下载&#xff0c;可能下载地址不同意。这些jar之间…

Python连接和操作Elasticsearch详细指南

Python连接和操作Elasticsearch详细指南 一、服务器端配置1. 修改 Elasticsearch 配置文件2. 开放防火墙端口 二、本地 Python 连接 Elasticsearch1. 连接 Elasticsearch2. 索引操作3. 文档操作4. 搜索内容5. 聚合查询6. 批量操作 三、注意事项四、故障排除结论 Elasticsearch …

获得日志记录之外的新视角:应用程序性能监控简介(APM)

作者&#xff1a;来自 Elastic David Hope 日志记录领域即将发生改变。在这篇文章中&#xff0c;我们将概述从单纯的日志记录到包含日志、跟踪和 APM 的完全集成解决方案的推荐流程。 通过 APM 和跟踪优先考虑客户体验 企业软件开发和运营已成为一个有趣的领域。我们拥有一些非…

Python - 面向对象;类和对象;方法属性;init,self;魔法方法;析构方法;函数方法区别(六)

一、面向对象编程&#xff08;OOP&#xff09; 定义 面向过程(Procedure Oriented Programming, POP)是一种程序设计范式&#xff0c;主要关注的是实现功能的步骤&#xff0c;设计时模块化和流程化。面向过程编程是一种以过程为中心的编程方式&#xff0c;它将问题分解成一系…

源码编译安装MySQL

MySQL相应版本的tar包下载 在5.7的版本的MySQL编译安装的时候&#xff0c;需要依赖C语言的库文件【boost】&#xff0c; 如上图所示&#xff0c;如果你使用第一个MySQL的tar包&#xff0c;还需要去网上去下载boost即C语言的库文件&#xff0c;但是第二个tar包就既包含MySQL的源…

关于Kubernetes(K8S)认证含金量?

Kubernetes越来越流行&#xff0c;目前它是市场上最佳的容器编排工具之一&#xff0c;也是运维工程师必备的技能之一。 大厂都在用K8S&#xff08;就业行情&#xff09; 虽说今年的大环境不是很好&#xff0c;但是从招聘数据来看&#xff0c;K8S岗位薪资不降反而上涨不…

Linux / Windows | ping IP + Port 测试

注&#xff1a;本文为 “Linux / Windows | ping IP Port 测试端口通畅” 相关文章合辑。 未整理去重。 windows 如何确认服务器上程序端口是否正常&#xff08;ping、tcping&#xff09; 三希已于 2023-05-22 18:08:06 修改 方式 1&#xff1a;ping 命令 ping 命令说明 p…

C++打造局域网聊天室第七课: Socket编程初步2

文章目录 前言一、Socket的API函数二、服务端建立Socket步骤总结 前言 C打造局域网聊天室第七课&#xff1a; Socket编程初步2 一、Socket的API函数 接着上一课的内容&#xff0c;我们在chartroom.cpp中找到如下位置 插入断点&#xff0c;运行 运行到断点处后&#xff0c;按…

vue-router路由传参的两种方式(params 和 query )

一、vue-router路由传参问题 1、概念&#xff1a; A、vue 路由传参的使用场景一般应用在父路由跳转到子路由时&#xff0c;携带参数跳转。 B、传参方式可划分为 params 传参和 query 传参&#xff1b; C、而 params 传参又可分为在 url 中显示参数和不显示参数两种方式&#x…

Docker Compose应用实战

文章目录 1、使用Docker Compose必要性及定义2、Docker Compose应用参考资料3、Docker Compose应用最佳实践步骤1_概念2_步骤 4、Docker Compose安装5、Docker Compose应用案例1_网站文件准备2_Dockerfile文件准备3_Compose文件准备4_使用docker-compose up启动容器5_访问6_常见…

el-table组件树形数据修改展开箭头

<style lang"scss" scoped> ::v-deep .el-table__expand-icon .el-icon-arrow-right:before {content: ">"; // 箭头样式font-size: 16px; }::v-deep .el-table__expand-icon{ // 没有展开的状态background-color: rgba(241, 242, 245, 1);color:…

5.2 JavaScript 案例 - 轮播图

JavaScript - 轮播图 文章目录 JavaScript - 轮播图基础模版一、刷新页面随机轮播图案例二、轮播图 定时器版三、轮播图完整版 基础模版 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta http-equiv"…