当前位置: 首页 > news >正文

结构型设计模式之Decorator(装饰器)

结构型设计模式之Decorator(装饰器)

前言:
本案例通过李四举例,不改变源代码的情况下 对“才艺”进行增强。

摘要:
摘要: 装饰器模式是一种结构型设计模式,允许动态地为对象添加功能而不改变其源代码。本文通过李四的才艺展示案例演示了该模式的应用。关键点包括:1)意图是动态添加职责,比继承更灵活;2)结构包含Component、ConcreteComponent、Decorator和ConcreteDecorator四个角色;3)适用于需要透明扩展对象功能、支持功能撤销或无法使用子类扩展的场景。代码示例展示了如何通过DecoratorA和DecoratorB在原有"画画"才艺基础上逐步添加"唱歌"和"跳舞"功能,体现了装饰器模式的逐层增强特性。运行结果验证了功能的动态叠加效果。

1)意图

动态的给一个对象添加一些额外的职责。就增加功能而言,Decorator模式比生成子类更加灵活。

2)结构

在这里插入图片描述

其中:

  • Component 定义一个对象接口,可以给这些对象动态的添加职责。
  • ConcreteComponent 定义一个对象,可以给这个对象添加一些职责。
  • Decorator 维持一个指向 Component 对象的指针,并定义一个与Component接口一致的接口。
  • ConcreteDecorator 向组件添加职责。

3)适用性

Decorator 模式适用于:

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤销的职责。
  • 当不能采用生成子类的方式进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是,由于定义被隐藏,或类定义不能用于生成子类。【了解】

4) 经典场景设计

1,在不修改现有对象结构的情况下扩展功能(核心场景):

当你需要给一个类添加新功能,但又不希望(或不能)修改这个类的源代码时(例如,类来自第三方库、是final类、修改风险高)。

当你需要给一个对象添加的功能是可选、可组合的,并且可能需要多种组合方式时。

例子: 给一个核心数据读写对象添加加密、压缩、缓存、日志记录、校验等功能。你可以自由组合这些装饰器(如 EncryptionDecorator(CompressionDecorator(CoreDataSource)))。

2,动态添加和撤销职责:

由于装饰器是组合关系,可以在运行时根据需要动态地给对象添加或移除装饰层。

例子: 一个文本编辑器中的文本格式化功能。基础 TextComponent 显示纯文本。你可以动态添加 BoldDecorator、ItalicDecorator、ColorDecorator 等来改变文本样式。移除装饰器即可撤销相应样式。

3,避免通过子类进行爆炸性扩展:

当功能组合的可能性非常多时,如果使用继承,需要为每一种可能的组合创建一个子类(如 EncryptedCompressedFile,CachedEncryptedFile,LoggedCachedFile 等),导致类数量急剧膨胀(“类爆炸”)。

装饰器模式通过组合,只需要定义每个独立功能的装饰器类,然后在运行时按需叠加,大大减少了类的数量。

例子: 图形用户界面(GUI)组件。基础组件如 SimpleWindow。功能如滚动条(ScrollbarDecorator)、边框(BorderDecorator)、标题栏(TitlebarDecorator)。你可以轻松创建带滚动条和边框的窗口(BorderDecorator(ScrollbarDecorator(SimpleWindow))),而无需创建 BorderedScrollableWindow 这样的特定子类。

4,为对象添加额外的行为,这些行为可能与核心逻辑正交:

有些行为(如日志记录、性能监控、权限检查、事务管理、缓存)是横切关注点,它们独立于对象的核心业务逻辑。

使用装饰器可以将这些横切关注点与核心逻辑解耦,使核心类更专注于自身职责,提高代码的模块化和可维护性。

例子: 在服务层或数据访问层接口上添加日志记录(LoggingServiceDecorator)或性能监控(TimingServiceDecorator)功能。核心 ConcreteService 实现业务逻辑,装饰器负责记录调用信息或耗时。

5,替代多重继承(在支持单继承的语言中尤其有用):

在Java、C#等单继承语言中,装饰器模式提供了一种模拟“拥有多个不同父类行为”的方式,通过组合叠加多个装饰器来实现。

例子: 一个游戏角色对象。基础角色有基本属性和行为。可以通过装饰器添加各种“Buff”或“Debuff”效果(如 SpeedBoostDecorator、InvisibleDecorator、PoisonedDecorator),这些效果可以叠加和移除。用继承很难优雅地实现这种动态、临时的效果叠加。

6,I/O流处理(最经典的实现之一):

Java的 java.io 包和 .NET的 System.IO 包是装饰器模式的教科书级应用。

基础组件如 FileInputStream / FileStream(读取字节/字节数组)。

装饰器如:

BufferedInputStream / BufferedStream:添加缓冲功能,提高效率。

DataInputStream:添加读取基本数据类型(int, float等)的功能。

GZIPInputStream / DeflateStream:添加解压缩功能。

ObjectInputStream:添加反序列化对象的功能。

你可以灵活组合:BufferedInputStream(FileInputStream) 提供缓冲的文件读取;DataInputStream(BufferedInputStream(FileInputStream)) 提供缓冲且能读基本数据类型的文件读取。

7,Web开发中的中间件/拦截器:

在Web框架(如Express.js/Koa.js, ASP.NET Core Middleware)中,处理HTTP请求/响应的管道(Pipeline)经常使用类似装饰器(或责任链+装饰)的思想。

每个中间件组件可以看作是一个装饰器,它接收一个代表核心处理逻辑(或下一个中间件)的“组件”,并在其前后添加自己的处理逻辑(如日志、认证、授权、异常处理、请求/响应转换、缓存)。

例子: AuthenticationMiddleware(AuthorizationMiddleware(LoggingMiddleware(CoreControllerHandler)))。

代码

/*** @author psd 结构性设计模式之装饰模式*/
public class DecoratorDemo {public static void main(String[] args) {Person lisi = new Student("lisi");lisi.operation();lisi = new DecoratorA(lisi);lisi.operation();System.out.println("-----------------------------");lisi = new DecoratorB(lisi);lisi.operation();}
}class DecoratorB extends Decorator {public DecoratorB(Person person) {this.person = person;}@Overridepublic void operation() {person.operation();System.out.println("跳舞");}
}class DecoratorA extends Decorator {public DecoratorA(Person person) {this.person = person;}@Overridepublic void operation() {person.operation();System.out.println("唱歌");}
}abstract class Decorator extends Person {protected Person person;
}class Student extends Person {public Student(String userName) {this.userName = userName;}@Overridepublic void operation() {System.out.println(userName + "才艺:画画");}
}abstract class Person {protected String userName;/*** 才艺描述*/public abstract void operation();
}

运行结果:
在这里插入图片描述

http://www.xdnf.cn/news/784945.html

相关文章:

  • new操作符具体做了什么
  • 枫之谷Artale端午节大当机----后端技术的巨大风险
  • 前端导入Excel表格
  • 新手小白使用VMware创建虚拟机练习Linux
  • 大宽带怎么做
  • 服务器租用:高防CDN和加速CDN的区别
  • 前端(vue)学习笔记(CLASS 7):vuex
  • 每天掌握一个Linux命令 - lsof
  • ES101系列09 | 运维、监控与性能优化
  • DrissionPage 性能优化实战指南:让网页自动化效率飞升
  • 2.3 关于async/await的原理介绍
  • word页眉添加下横线以及部分内容右对齐问题
  • 隧道监测预警系统:构筑智慧交通的安全中枢
  • 在Mathematica中实现Newton-Raphson迭代
  • 归并排序:高效稳定的分治算法
  • Qwen2.5-VL 损失函数
  • 今日行情明日机会——20250603
  • 【Linux基础知识系列】第八篇-基本网络配置
  • 涂装协作机器人:重新定义涂装工艺的智能化未来
  • 网络交换机:构建高效、安全、灵活局域网的基石
  • 无人机甲烷检测技术革新:开启环境与能源安全监测新时代
  • 【从0-1的HTML】第2篇:HTML标签
  • 颈部的 “异常坚持”
  • 悟饭游戏厅iOS版疑似流出:未测试版
  • 08.MySQL复合查询详解
  • CAMEL-AI开源自动化任务执行助手OWL一键整合包下载
  • 鸿蒙版Taro 搭建开发环境
  • 74. 搜索二维矩阵 (力扣)
  • React 第五十二节 Router中 useResolvedPath使用详解和注意事项示例
  • 制作一款打飞机游戏64:关卡设计