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

一、装饰模式

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.mzph.cn/web/62476.shtml

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

相关文章

Cmake+基础命令

一、版本要求&#xff1a; 检查 cmake 版本号的最低要求&#xff0c;不满足条件时报错。 cmake_minimum_required(VERSION <version>)参数&#xff1a; version&#xff1a;最低要求的版本号 例子&#xff1a; # 最低要求安装3.21版本的cmake cmake_minimum_required…

Java——容器(单例集合)(上)

一 容器介绍 容器&#xff0c;是用来容纳物体、管理物体。生活中,我们会用到各种各样的容器。如锅碗瓢盆、箱子和包等 程序中的“容器”也有类似的功能&#xff0c;用来容纳和管理数据。比如&#xff0c;如下新闻网站的新闻列表、教育网站的课程列表就是用“容器”来管理 视频…

word poi-tl 表格功能增强,实现表格功能垂直合并

目录 问题解决问题poi-tl介绍 功能实现引入依赖模版代码效果图 附加&#xff08;插件实现&#xff09;MergeColumnData 对象MergeGroupData 类ServerMergeTableData 数据信息ServerMergeTablePolicy 合并插件 问题 由于在开发功能需求中&#xff0c;word文档需要垂直合并表格&…

OpenCV相机标定与3D重建(11)机器人世界手眼标定函数calibrateRobotWorldHandEye()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算机器人世界/手眼标定&#xff1a; w T b _{}^{w}\textrm{T}_b w​Tb​ 和 c T g _{}^{c}\textrm{T}_g c​Tg​。 cv::calibrateRobotWorldHa…

GPT系列模型简要概述

GPT-1&#xff1a;&#xff08;0.117B参数量&#xff0c;0.8B words预训练数据) 动机&#xff1a; 在RNN和Transformer之间&#xff0c;选择了后者。 和《All your need is Attention》翻译模型的Encoder-Decoder架构相比&#xff0c;只保留Decoder&#xff0c;因此去掉了Cross…

汽车升级到底应不应该设置“可取消“功能

最近&#xff0c;汽车OTA&#xff08;Over-the-Air&#xff09;升级频频成为车主讨论的热点。有些车主反映&#xff0c;一些升级增加了实用功能&#xff0c;而另一些却让体验变得复杂甚至带来不便。于是&#xff0c;大家不禁发问&#xff1a;汽车升级功能究竟应不应该允许“可取…

单片机 PCB 设计要点

一、引言 单片机作为现代科技的重要组成部分&#xff0c;其 PCB 设计至关重要。本文将详细介绍单片机 PCB 设计的要点和流程&#xff0c;帮助读者更好地掌握这一关键技术。 在电子世界的浩瀚星海中&#xff0c;单片机无疑是现代科技中一颗闪烁的明珠。作为掌握嵌入式系统的基…

Django+Apscheduler 开发定时任务模块【六】

目录 回顾 前五个文章讲述了django-autojob的部分代码和执行逻辑 【DjangoApscheduler 开发定时任务模块】【一】 【DjangoApscheduler 开发定时任务模块】【二】 【DjangoApscheduler 开发定时任务模块】【三】 【DjangoApscheduler 开发定时任务模块】【四】 【DjangoApsch…

Ubuntu中配置交叉编译工具的三条命令的详细研究

关于该把下面的三条交叉编译配置语句加到哪里&#xff0c;详情见 https://blog.csdn.net/wenhao_ir/article/details/144326545 的第2点。 现在试解释下面三条交叉编译配置语句&#xff1a; export ARCHarm export CROSS_COMPILEarm-buildroot-linux-gnueabihf- export PATH$…

wlanapi.dll丢失怎么办?有没有什么靠谱的修复wlanapi.dll方法

在遇到各种系统文件错误当中&#xff0c;其中之一就是“wlanapi.dll文件丢失”的问题。这种问题通常发生在Windows操作系统上&#xff0c;特别是当系统试图执行与无线网络相关的任务时。wlanapi.dll是一个重要的系统文件&#xff0c;它负责处理Windows无线网络服务的许多功能。…

利用ipmi工具设置ip、用户等设置

#打开交互模式 ipmitool -I open shell #切换管理端口为lom1&#xff0c;即共享em1/eth0 delloem lan set shared with lom1 #设置ip、mask、gateway lan set 1 ipaddr 10.0.0.250 lan set 1 netmask 10.0.0.250 lan set 1 defgw ipaddr 10.0.0.250 #查看用户名 user list 1 …

Python之因子分析详细步骤

1.数学原理 1.1数学模型 1.2正交因子模型假设 注意&#xff1a;下面的推导都是基于这一假设。因此&#xff0c;这里的模型都是属于正交因子模型。 1.3正交因子模型的协方差结构 1.4各类方差贡献的介绍 在1.3正交因子模型的协方差结构中&#xff0c;我们介绍了“方差贡献”&…

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

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

linux之vim

一、模式转换命令 vim主要有三种模式&#xff1a;命令模式&#xff08;Normal Mode&#xff09;、输入模式&#xff08;Insert Mode&#xff09;和底线命令模式&#xff08;Command-Line Mode&#xff09;。 从命令模式切换到输入模式&#xff1a;i&#xff1a;在当前光标所在…

显存和GPU之间的通信;GPUDirect P2P,NVLink,NCCL;聚合通信和点对点通信

目录 显存和GPU之间的分配 显存和GPU之间的通信 原语是什么,简单举例说明 GPUDirect P2P,NVLink,NCCL的全称及解释 聚合通信和点对点通信 聚合通信(Collective Communication) 点对点通信(Point-to-Point Communication) 为什么使用GPUDirect P2P,NVLink,NCCL…

Mysql 的 B+ 树是否包含行数据?

在 MySQL 中&#xff0c;是否在 B树 的叶子节点上存储完整的行数据&#xff0c;取决于使用的 存储引擎 和 索引类型&#xff1a; 聚簇索引 (Clustered Index) 叶子节点包含完整的行数据。 适用场景&#xff1a;MySQL InnoDB 存储引擎的主键索引&#xff08;或聚簇索引&#xf…

【记录】用JUnit 4的@Test注解时报错java.lang.NullPointerException的原因与解决方法

项目场景&#xff1a; 在练习黑马点评的逻辑过期解决缓存击穿时&#xff0c;编写了一个预热缓存数据的单元测试 SpringBootTest public class HmDianPingApplicationTests {Resourceprivate ShopServiceImpl shopService;Testpublic void testSaveShop() throws InterruptedE…

echarts使用整理

4、条形分区统计 <div ref"chartsVal1" class"chartsline-div"></div> const chartsVal1 ref(null); const chartsVal1Title ref(运行时间统计);drewCharts2(chartsVal1, chartsVal1Title.value);function drewCharts2(id, title) {const m…

【八股】HTTP

浏览器输入URL之后发生的过程 浏览器解析URL中的协议&#xff0c;主机&#xff0c;端口&#xff0c;路径参数等DNS域名解析得到对应的IP地址通过IP和PORT对服务器发送TCP三次握手建立连接浏览器发送请求服务器接受请求&#xff0c;处理并响应浏览器得到HTTP响应&#xff0c;对…

torch.optim.lr_scheduler.ReduceLROnPlateau

torch.optim.lr_scheduler.ReduceLROnPlateau 是 PyTorch 中的一种学习率调度器&#xff0c;主要用于在模型训练过程中根据某些指标&#xff08;如验证损失&#xff09;动态调整学习率。它是一种基于性能指标动态调整学习率的策略&#xff0c;而不是预定义的固定时间调整。 主要…