设计模式-装饰者模式(Decorator)

1. 概念

  • 装饰者模式是一种结构型设计模式,它允许用户在不修改原始对象的基础上,通过将对象包装在装饰者类的对象中,动态地给原始对象添加新的行为或职责。

2. 原理结构图

图1
在这里插入图片描述
图2
在这里插入图片描述

  • 抽象组件(Component):定义了对象的接口,可以给这些对象动态地增加职责。
  • 具体组件(ConcreteComponent):是实现抽象组件接口的具体对象,它是被装饰器装饰的原始对象。
  • 抽象装饰器(Decorator):是所有装饰器的抽象父类,它实现了抽象组件的接口,并持有一个抽象组件的引用。
  • 具体装饰器(ConcreteDecorator):是具体的装饰器类,它实现了向被装饰对象添加功能的方法。
  • 注意:如图2,如果ConcreteComponent类很多,还可以在Component与ConcreteComponent之间设计一个缓冲层,将共有的部分提取出来,抽象层一个类CommonConcreteComponent

3. 代码示例

3.1 示例1
  • 在这个例子中,有一个Component接口,一个实现了该接口的ConcreteComponent类,以及两个实现了Decorator接口的装饰者类ConcreteDecoratorA和ConcreteDecoratorB。
// Component 接口  
interface Component {  void operation();  
}  // ConcreteComponent 类,实现了 Component 接口  
class ConcreteComponent implements Component {  @Override  public void operation() {  System.out.println("ConcreteComponent operation");  }  
}  // Decorator 接口,继承了 Component 接口  
interface Decorator extends Component {  void addedState();  
}  // ConcreteDecoratorA 类,实现了 Decorator 接口,并持有一个 Component 对象的引用  
class ConcreteDecoratorA implements Decorator {  private Component component;  public ConcreteDecoratorA(Component component) {  this.component = component;  }  @Override  public void operation() {  // 调用 Component 对象的 operation() 方法  component.operation();  // 添加新的功能或行为  addedState();  }  @Override  public void addedState() {  System.out.println("ConcreteDecoratorA addedState");  }  
}  // ConcreteDecoratorB 类,同样实现了 Decorator 接口,并持有一个 Component 对象的引用  
class ConcreteDecoratorB extends ConcreteDecoratorA {  public ConcreteDecoratorB(Component component) {  super(component);  }  @Override  public void addedState() {  // 调用父类的 addedState() 方法  super.addedState();  // 添加新的功能或行为  System.out.println("ConcreteDecoratorB addedState");  }  
}  // 测试类  
public class DecoratorPatternDemo {  public static void main(String[] args) {  Component component = new ConcreteComponent();  // 使用 ConcreteDecoratorA 装饰 component  ConcreteDecoratorA decoratorA = new ConcreteDecoratorA(component);  decoratorA.operation();  // 使用 ConcreteDecoratorB 装饰 component,这里其实是通过 ConcreteDecoratorA 进行装饰的,形成链式装饰  ConcreteDecoratorB decoratorB = new ConcreteDecoratorB(decoratorA);  decoratorB.operation();  }  
}
  • 在这个示例中,ConcreteComponent类有一个operation()方法,该方法执行一些基本操作。ConcreteDecoratorA和ConcreteDecoratorB类都扩展了这个功能,通过在operation()方法中添加额外的行为来实现。ConcreteDecoratorB还通过继承ConcreteDecoratorA来组合多个装饰者的功能。
  • 运行DecoratorPatternDemo类的main方法,你将看到如下输出:
ConcreteComponent operation  
ConcreteDecoratorA addedState  
ConcreteComponent operation  
ConcreteDecoratorA addedState  
ConcreteDecoratorB addedState

3.2 示例2
  • 具体案例:展示如何使用装饰者模式为一个文本编辑器(TextEditor)添加不同的功能,如字体加粗(BoldDecorator)、字体斜体(ItalicDecorator)和下划线(UnderlineDecorator)。
// Component 接口
interface TextEditorComponent {String writeText(String text);
}// ConcreteComponent 类,实现 TextEditorComponent 接口
class SimpleTextEditor implements TextEditorComponent {@Overridepublic String writeText(String text) {return "Simple Text: " + text;}
}// Decorator 抽象类
abstract class TextEditorDecorator implements TextEditorComponent {protected TextEditorComponent textEditor;public TextEditorDecorator(TextEditorComponent textEditor) {this.textEditor = textEditor;}@Overridepublic String writeText(String text) {return textEditor.writeText(text);}
}// BoldDecorator 类,添加字体加粗功能
class BoldDecorator extends TextEditorDecorator {public BoldDecorator(TextEditorComponent textEditor) {super(textEditor);}@Overridepublic String writeText(String text) {return "<b>" + super.writeText(text) + "</b>";}
}// ItalicDecorator 类,添加字体斜体功能
class ItalicDecorator extends TextEditorDecorator {public ItalicDecorator(TextEditorComponent textEditor) {super(textEditor);}@Overridepublic String writeText(String text) {return "<i>" + super.writeText(text) + "</i>";}
}// UnderlineDecorator 类,添加下划线功能
class UnderlineDecorator extends TextEditorDecorator {public UnderlineDecorator(TextEditorComponent textEditor) {super(textEditor);}@Overridepublic String writeText(String text) {return "<u>" + super.writeText(text) + "</u>";}
}// 测试类
public class TextEditorPatternDemo {public static void main(String[] args) {// 创建一个简单的文本编辑器对象TextEditorComponent simpleEditor = new SimpleTextEditor();// 使用装饰者来增强文本编辑器的功能TextEditorComponent boldEditor = new BoldDecorator(simpleEditor);TextEditorComponent italicEditor = new ItalicDecorator(boldEditor);TextEditorComponent underlineEditor = new UnderlineDecorator(italicEditor);// 使用增强后的文本编辑器写入文本String text = "Hello, Decorator Pattern!";String decoratedText = underlineEditor.writeText(text);// 输出结果System.out.println(decoratedText);}
}
  • 运行 TextEditorPatternDemo 类的main方法,你将看到如下输出:
<u><i><b>Simple Text: Hello, Decorator Pattern!</b></i></u>
  • 在这个例子中,创建了一个简单的文本编辑器,并通过装饰者链动态地为其添加了字体加粗、斜体和下划线功能。装饰者模式允许根据需要在运行时组合不同的装饰者,从而灵活地增强对象的功能。这种灵活性使得装饰者模式在处理复杂场景时非常有用。

4. 优缺点

  • 主要作用
    • 动态地增强对象的功能,通过组合不同的装饰者实现功能的灵活扩展,同时保持代码的稳定性和可维护性,且对客户端透明。
  • 优点
    • 扩展灵活:装饰者模式提供了比继承更加灵活的扩展方式。通过装饰者模式,可以在不改变原有类的基础上,为对象动态添加额外的功能。
    • 即插即用:装饰者模式允许用户按需添加功能,这些功能可以即时生效,不需要对原有系统进行大量修改。
    • 组合灵活:可以通过不同的装饰者类及其排列组合,实现多种不同的功能扩展,这样可以灵活地满足不同的需求场景。
    • 遵守开闭原则:装饰者模式遵循了软件设计的开闭原则,即对扩展开放,对修改封闭。这意味着系统可以很容易地进行扩展,而不需要修改现有的代码。
  • 缺点
    • 复杂性增加:虽然装饰者模式提供了灵活性,但同时也可能增加系统的复杂性。因为需要理解如何将多个装饰者组合在一起,以及它们之间的交互方式。
    • 设计难度:正确实现装饰者模式可能需要更细致的设计和规划,尤其是在确定哪些功能应该由哪个装饰者负责时。
    • 调试困难:由于装饰者模式在运行时动态添加功能,这可能会使得问题的定位和调试变得更加困难。
    • 性能考虑:频繁地使用装饰者模式可能会导致性能问题,特别是在装饰者数量较多或者装饰逻辑复杂时。

5. 应用场景

5.1 主要包括以下几个方面
  1. 动态扩展功能:当需要动态地给一个对象增加一些额外的职责或功能时,装饰者模式非常适用。这些功能可以在运行时根据需要添加或撤销,提供了比继承更有弹性的替代方案。
  2. 避免子类爆炸:在使用继承来实现功能扩展时,随着功能的增多,子类可能会变得非常庞大和复杂,导致所谓的“子类爆炸”问题。装饰者模式通过在不改变原有对象结构的基础上添加功能,有效地避免了这个问题。
  3. 灵活组合功能:当需要组合多个功能或职责时,装饰者模式允许将不同的装饰者对象链接在一起,形成一个功能强大的对象。这种组合方式可以产生各种复杂的功能组合,以满足不同的需求。
  4. 透明的功能增强:装饰者模式允许对原始对象进行透明的包装和增强,即客户端可以像使用原始对象一样使用装饰后的对象,而无需关心其内部实现细节。这使得装饰者模式在保持原有接口不变的情况下,为对象增加了新的功能。

5.2 实际应用
  1. 用户界面定制
    • 实例:在开发一个图形用户界面(GUI)应用程序时,可以使用装饰者模式为按钮、文本框等组件添加不同的样式或行为。比如,可以给一个按钮添加不同的背景色、字体或点击事件处理器,而无需修改按钮本身的代码。
  2. 权限控制
    • 实例:在一个系统中,可以使用装饰者模式为特定的操作添加权限控制。例如,可以为一个用户管理类添加一个装饰者,用于检查用户是否具有执行特定操作的权限。
  3. 文件处理
    • 实例:在处理文件时,可能需要为文件添加不同的处理方式,如加密、压缩等。可以使用装饰者模式来动态地为文件对象添加这些功能。每个装饰者都可以负责一种特定的处理方式,通过组合多个装饰者,可以实现复杂的文件处理流程。
  4. 手机配件
    • 实例:在手机的使用过程中,用户可以通过添加各种配件来增强手机的功能,如手机壳、钢化膜、耳机等。这些配件可以看作是手机的装饰者,它们为手机增加了额外的保护、美观或音频输出等功能。
  5. 电影特效
    • 实例:在电影制作中,特效团队会为影片添加各种视觉效果,如烟雾、爆炸、光影等。这些特效可以看作是影片的装饰者,它们为影片增添了视觉冲击力和观赏性。

6. JDK中的使用

  • Java I/O中的流
    • InputStream 是一个抽象的组件接口,而 FileInputStream 是它的一个具体实现。为了提供额外的功能,如缓冲或过滤,可以使用装饰者模式来动态地添加这些功能,而不是修改 FileInputStream 类本身。这样的设计使得I/O流非常灵活,可以通过组合不同的装饰者来实现复杂的功能。
      在这里插入图片描述
  • InputStream和其子类:InputStream 是装饰者模式中的抽象组件(Component)。FileInputStream、ByteArrayInputStream、ObjectInputStream 等直接继承自 InputStream 的类相当于装饰者模式中的具体组件(ConcreteComponent)。
  • BufferedReader和其他装饰类:BufferedReader 是 Reader 的一个装饰类,它增加了缓冲区来提高字符读取的效率。同样,BufferedWriter 对 Writer 也有类似的装饰作用。
  • FilterInputStream:这个类是 InputStream 的装饰者,它提供了一些额外的功能,比如可以添加其他输入流的装饰者。

7. 注意事项

  • 保持接口的一致性:装饰者和被装饰对象应该具有相同的接口,这样客户端代码就可以透明地使用它们,无需关心具体是装饰者还是被装饰对象。这有助于保持代码的简洁性和一致性。
  • 避免装饰者之间的依赖:装饰者之间应该保持独立,避免产生复杂的依赖关系。这样可以确保装饰者可以单独使用或组合使用,而不会引入额外的复杂性。
  • 装饰者的顺序:当使用多个装饰者时,它们的顺序可能会影响最终的结果。因此,在设计时需要考虑装饰者的顺序问题,并确保它们能够正确地组合在一起。
  • 角色定义:明确定义不同的角色,包括抽象组件(Component)、具体组件(ConcreteComponent)和装饰者(Decorator),以确保每个部分的职责清晰。
  • 避免过度设计:虽然装饰者模式提供了强大的功能扩展能力,但不应过度使用,以免引入不必要的复杂性和性能开销。
  • 适用场景评估:在考虑使用装饰者模式之前,应评估是否真的需要动态添加功能,以及这些功能是否可以在不影响现有系统的情况下撤销或修改。

8. 生成器模式 VS 组合模式 VS 装饰器模式

模式目的模式架构主要角色应用场景
建造者模式分步构建复杂对象指挥者,生成器构建具有复杂逻辑的对象
组合模式表示具有层次结构的对象组合类和叶子节点树形结构和递归结构
装饰器模式动态添加新功能抽象组件和装饰器功能组合和扩展

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

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

相关文章

离散化实现低通滤波器(选用双线性变换)

学习了离散化后整理了其中的核心步骤&#xff0c;此处不对原理进行深究&#xff0c;仅仅介绍如何对一个连续系统进行离散化 此处可以得到低通滤波器的截止频率为1000rad/s. 离散化的过程为将s 2/Ts * [(z - 1) / (z 1)] (选用双线性变换) 得到离散化序列为 Y(z) [w…

Python-VBA函数之旅-bytearray函数

目录 1、bytearray函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、相关文章&#xff1a; 个人主页&#xff1a;非风V非雨-CSDN博客 bytearray函数在Python中提供了一种可变字节序列的表示方式&#xff0c;这在实际编程中有多种应用场景。常见的应用场…

如何用Python编写简单的网络爬虫(页面代码简单分析过程)

一、什么是网络爬虫 在当今信息爆炸的时代&#xff0c;网络上蕴藏着大量宝贵的信息&#xff0c;如何高效地从中获取所需信息成为了一个重要课题。网络爬虫&#xff08;Web crawler&#xff09;作为一种自动化工具&#xff0c;可以帮助我们实现这一目标&#xff0c;用于数据分析…

项目实战 | 使用python分析Excel销售数据(用groupby)

项目实战 | 使用python分析Excel销售数据 本文目录&#xff1a; 零、00时光宝盒 一、提出问题 二、理解数据 2.1、安装python读取excel文件的库 2.2、查看excel表的字段名和前几行记录 2.3、查看excel表结构 2.4、查看索引 2.5、查看每一列的列表头内容 2.6、查看每一…

移除元素Java实现

题意 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 额外空间 并 原地 修改数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元…

websocket实践

文章目录 背景WebSocket API使用场景优点 实例步骤 1: 设置 WebSocket 服务器步骤 2: 创建客户端 HTML 页面步骤 3: 测试 WebSocket 通信注意事项实际操作 参考资料 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。它使得浏览器和服务器只需建立一个连接&#xff0c;…

CSS:filter属性介绍

一、filter属性简介 值描述示例blur(Npx)设置高斯模糊效果。N是模糊半径&#xff0c;值越大&#xff0c;模糊效果越明显。filter: blur(5px);brightness(%)调整图像的亮度。百分比值小于100%会使图像变暗&#xff0c;大于100%会使图像变亮。filter: brightness(75%);contrast(…

el-table合计行添加按钮操作

针对于el-table中合计功能中的操作栏也可以按钮&#xff0c;并且可以添加点击事件 ElTable源码里footer部分是&#xff0c;这种方式渲染的&#xff0c;也就是 支持传递VNode。使用h第一个参数传递 组件&#xff0c;可以把组件转成VNode&#xff0c;比如现在要在右下角加一个 详…

无货源,0基础做电商,6个选品逻辑快速出单!

首先我们要先解决货源问题&#xff0c;再来谈选品逻辑。初入电商行业&#xff0c;进货渠道建议使用1688。首先1688是国内最大的B2B批发平台&#xff0c;平台服务和安全性都提供了一定的保障&#xff0c;以及丰富的货源选择。你可以浏览不同供应商的产品&#xff0c;对比价格、质…

如何关闭WordPress的自动更新功能

Wordpress为什么自动更新 WordPress自动更新是为了提供更好的安全性和稳定性。 安全性&#xff1a;WordPress是一个广泛使用的内容管理系统&#xff0c;因此成为恶意攻击的目标。WordPress的自动更新功能确保你的网站及时获得最新的安全补丁和修复程序&#xff0c;以保护你的网…

【智能优化算法】基于领导者优化的哈里斯鹰优化算法(LHHO)

01.引言 基于领导者优化的哈里斯鹰优化算法leader Harris hawks optimization (LHHO)&#xff0c;以增强Harris hawks optimization (HHO)的搜索能力。通过在探索阶段的适应性栖息和每一代哈里斯鹰的基于领导者的突变选择&#xff0c;可以实现更多的探索。使用经典的23个基准函…

Flink常见面试问题(附答案)

目录 基础篇1. 什么是Apache Flink&#xff1f;2. Flink与Hadoop的区别是什么&#xff1f;3. Flink中的事件时间&#xff08;Event Time&#xff09;和处理时间&#xff08;Processing Time&#xff09;有什么区别&#xff1f;4. Flink的容错机制是如何实现的&#xff1f;5. 什…

node.js 包管理工具介绍 (npm与Yarn详细说明)

一、什么是包&#xff1f; 包&#xff08;package&#xff09;代表了一组特定功能的源码集合 二、什么是包管理工具&#xff1f; 也就是管理包的应用软件&#xff0c;可以对包进行下载、更新、删除、上传等操作。借助包管理工具&#xff0c;可以快速开发项目提升开发效率。包…

4.2.4 理解路由器数据包过程

1、实验目的 通过本实验可以掌握&#xff1a; 了解IP路由原理了解数据包封装和解封装的概念了解路由器路由和交换过程 2、实验拓扑 观察路由器路由数据包过程的实验拓扑如图4-3所示&#xff0c;设备接口地址信息如表4-2所示。 图4-3 观察路由器路由数据包过程的实验拓扑 本…

用Python编写GUI程序实现WebP文件批量转换为JPEG格式

在Python编程中&#xff0c;经常会遇到需要处理图片格式的情况。最近&#xff0c;我遇到了一个有趣的问题&#xff1a;如何通过编写一个GUI程序来实现将WebP格式的图片批量转换为JPEG格式&#xff1f;在这篇博客中&#xff0c;我将分享我使用Python、wxPython模块和Pillow库实现…

linux系统离线安装nginx

perlnginx是一个高性能的http和反向代理服务器&#xff0c;并发能力很强&#xff0c;一般用来做负载均衡比较多&#xff0c;分布式系统开发中用作web服务器。 一、下载 地址&#xff1a;nginx: download 我们下载这个稳定版本 二、环境依赖检查 nginx安装需要很多外部依赖&…

python开发poc,fofa爬虫批量化扫洞

学习使用python做到批量化的漏洞脚本 1.通过fofa搜索结果来采集脚本 2.批量化扫描漏洞 ---glassfish存在任意文件读取在默认48484端口&#xff0c;漏洞验证的poc为: "glassfish" && port"4848" && country"CN" http://loca…

Sybase ASE中的char(N)的坑以及与PostgreSQL的对比

1背景 昨天,一朋友向我咨询Sybase ASE中定长字符串类型的行为,说他们的客户反映,同样的char类型的数据,通过jdbc来查,Sybase库不会带空格,而PostgreSQL会带。是不是这样的?他是PostgreSQL的专业大拿,但因为他手头没有现成的Sybase ASE环境,刚好我手上有,便于一试。 …

Python实现读取dxf文件的所有字符

Python实现读取dxf文件的所有字符 import ezdxfdef read_dxf_and_print_text(filename):# 加载DXF文件doc ezdxf.readfile(filename)# 遍历所有的实体for entity in doc.entities:# 检查实体是否是TEXT、MTEXT或DIMENSIONif isinstance(entity, ezdxf.entities.Text):print(f…

计算机视觉——图像特征提取D2D先描述后检测特征提取算法原理

概述 局部特征提取是计算机视觉中的一个重要任务&#xff0c;它旨在从图像中提取出能够代表图像局部结构和外观信息的特征。这些特征通常用于图像匹配、物体识别、三维重建、跟踪和许多其他应用。传统方法&#xff0c;如尺度不变特征变换&#xff08;SIFT&#xff09;&#xf…