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

一、装饰模式

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、总结

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

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

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

相关文章

【Elasticsearch】实现用户行为分析

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

Linux评估网络性能

网络性能直接影响应用程序对外提供服务的稳定性和可靠性 ping命令检测网络的连通性 如果网络反应缓慢&#xff0c;或连接中断&#xff0c;可以用ping来测试网络的连通情况 time值(单位为毫秒)显示了两台主机之间的网络延时情况。如果此值很大&#xff0c;则表示网络的延时很大…

工业智能网关如何为企业实现智能制造赋能?

在数字化转型的浪潮中&#xff0c;工业智能网关作为连接物理世界与数字世界的桥梁&#xff0c;正逐步成为智能制造领域的核心组件。本文将通过一个实际使用案例&#xff0c;深入剖析工业智能网关如何助力企业实现生产流程的优化、数据的高效采集与分析&#xff0c;以及智能化决…

【LLMs】用LM Studio本地部署离线大语言模型

文章目录 一、下载LM Studio二、下载大语言模型1. 查看模型介绍2. 点击模型文件进行下载2.1 完整下载2.2 部分下载 三、加载模型1. 打开LM Studio图形化界面&#xff0c;点击**My Models**2. 然后&#xff0c;点击“...”&#xff0c;选择“change”&#xff0c;选择刚下载好的…

Python_Flask04(牛马问答平台01)

项目名称&#xff1a;牛马问答平台 项目简介&#xff1a;1.主要用来给社会上的牛马们探讨老板的恶心之处。 2. 用来学习交流。 技术手段&#xff1a;Python3.x Flask render_template pymysql flask_sqlalchemy........ 注意该博客为迭代项目&#xff0c;于最后一期展示完整…

【时时三省】(C语言基础)结构体内存对齐练习题

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 练习一 这个输出结果是8 练习二 这个输出结果是16 练习三 这个输出结果是32 上面的输出结果都是根据结构体对齐规则来计算的

在ARM Linux应用层下使用SPI驱动WS2812

文章目录 1、前言2、结果展示3、接线4、SPI驱动WS2812原理4.1、0码要发送的字节4.2、1码要发送的字节4.3、SPI时钟频率 5、点亮RGB5.1、亮绿灯5.2、亮红灯5.3、亮蓝灯5.4、完整程序 6、RGB呼吸灯7、总结 1、前言 事情是这样的&#xff0c;前段时间&#xff0c;写了一个基于RK3…

unity3d—demo(2d人物左右移动发射子弹)

目录 人物代码示例&#xff1a; 子弹代码示例&#xff1a; 总结上面代码&#xff1a; 注意点&#xff1a; 人物代码示例&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine;public class PlayerTiao : MonoBehaviour {public f…

Python subprocess.run 使用注意事项,避免出现list index out of range

在执行iOS UI 自动化专项测试的时候&#xff0c;在运行第一遍的时候遇到了这样的错误&#xff1a; 2024-12-04 20:22:27 ERROR conftest pytest_runtest_makereport 106 Test test_open_stream.py::TestOpenStream::test_xxx_open_stream[iPhoneX-xxx-1-250] failed with err…

怎么样能使Ubuntu的文件浏览器显示当前目录的路径,而不是只显示一个文件名?

默认情况下Ubuntu的文件浏览器是只显示当前目录的目录名的&#xff0c;这很不便我们查看路径或直接利用路径进行定位&#xff0c;那么怎么样能使Ubuntu的文件浏览器显示当前目录的路径呢&#xff1f; 两种方法&#xff1a; 第1种-临时方法 按下快捷键 Ctrl L&#xff0c;导航…

自制shell命令行解释器,深入理解Linux系统命令行实现原理

个人主页&#xff1a;敲上瘾-CSDN博客 个人专栏&#xff1a;Linux学习、游戏、数据结构、c语言基础、c学习、算法 目录 ​编辑 1.打印命令提示符 ​编辑 2.获取用户输入指令 3.重定向分析 4.命令行参数表与环境变量表 5.命令解析 6.命令执行 6.1.创建子进程 6.2.文件…

LangChain:大模型AI应用开发的强大引擎

文章目录 LangChain的核心功能LangChain的典型使用场景LangChain的未来展望《LangChain大模型AI应用开发实践》编辑推荐内容简介作者简介目录 在人工智能领域&#xff0c;大型语言模型&#xff08;LLMs&#xff09;的应用开发正逐渐成为技术前沿的热门话题。随着技术的不断进步…

【MFC】vs2019中使用sqlite3完成学生管理系统

目录 效果图list Contral 控件的简单使用使用sqlite3 效果图 使用sqlite3完成简单的数据库操作。 list Contral 控件的简单使用 本章只介绍基本应用 添加表头&#xff1a;语法&#xff1a; int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat LVCFMT_LEFT…

杨振宁大学物理视频中黄色的字,c#写程序去掉

先看一下效果&#xff1a;&#xff08;还有改进的余地&#xff09; 我的方法是笨方法&#xff0c;也比较刻板。 1&#xff0c;首先想到&#xff0c;把屏幕打印下来。c#提供了这样一个函数&#xff1a; Bitmap bmp new Bitmap(640, 480, PixelFormat.Format32bppArgb); // 创…

Android 逆向/反编译/Hook修改应用行为 基础实现

前言&#xff1a;本文通过一个简单的情景案例实现安卓逆向的基本操作 一、情景描述 本文通过一个简单的情景案例来实现安卓逆向的基本操作。在这个案例中所使用的项目程序是我自己的Demo程序&#xff0c;不会造成任何的财产侵害&#xff0c;本文仅作为日常记录及案例分享。实…

OSCP - Proving Grounds - Zino

主要知识点 SMB知识python脚本提权 具体步骤 执行nmap Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-10 01:24 UTC Nmap scan report for 192.168.52.64 Host is up (0.00077s latency). Not shown: 65529 filtered tcp ports (no-response) PORT STATE SER…

VLA模型

目录 引言1. 机器人大模型面临的挑战2. 目前的数据集2.1 RT-12.2 Open X-Embedding2.3 DROID 3. 目前的VLA模型3.1 Goat3.2 RT-13.2.1 总体架构3.2.2 效果 3.3 RT-23.3.1 总体架构3.3.2 效果 3.4 RT-X3.4.1 模型效果1). RT-1-X2). RT-2-X 3.5 RT-H3.5.1 总体架构3.5.2 效果 3.6…

aws(学习笔记第十六课) 使用负载均衡器(ELB)解耦webserver以及输出ELB的日志到S3

aws(学习笔记第十六课) 使用负载均衡器(ELB)以及输出ELB的日志到S3 学习内容&#xff1a; 使用负载均衡器(ELB)解耦web server输出ELB的日志到S3 1. 使用负载均衡器(ELB) 全体架构 使用ELB(Elastic Load Balancer)能够解耦外部internet访问和web server之间的耦合&#xff0c…

如何使用Java编写Jmeter函数

Jmeter 自带有各种功能丰富的函数&#xff0c;可以帮助我们进行测试&#xff0c;但有时候提供的这些函数并不能满足我们的要求&#xff0c;这时候就需要我们自己来编写一个自定义的函数了。例如我们在测试时&#xff0c;有时候需要填入当前的时间&#xff0c;虽然我们可以使用p…

实战指南:如何通过WBS提高项目估算准确性?

通过WBS将复杂任务细分为更易管理的任务&#xff0c;这有助于明确每项工作范围、所需资源及时间&#xff0c;从而减少估算误差&#xff0c;制定更现实的预算和时间表&#xff0c;提升团队协作效率。如果没有通过WBS将任务细化&#xff0c;项目范围可能变得模糊不清&#xff0c;…