【设计模式-3.5】结构型——装饰器模式

article/2025/7/5 19:49:36

说明:本文介绍结构型设计模式之一的装饰器模式

定义

装饰器模式(Decorator Pattern)也叫作包装器模式(Wrapper Pattern),指再不改变原有对象的基础上,动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活,属于结构型设计模式。(引自《设计模式就该这样学》P201)

化妆例子

以女孩化妆为例,如下:

(可展示接口,Showable)

/*** 能展示的*/
public interface Showable {/*** 展示方法*/void show();
}

(女生对象,Girl)

/*** 女生对象*/
public class Girl implements Showable {@Overridepublic void show() {System.out.print("女孩素颜的面容");}
}

(装饰类,Decorator)

/*** 装饰类*/
public class Decorator implements Showable {private Showable showable;/*** 构造器注入*/public Decorator(Showable showable) {this.showable = showable;}@Overridepublic void show() {System.out.print("抹上淡淡的粉底【");showable.show();System.out.print("】");}
}

(客户端,Client)

public class Client {public static void main(String[] args) {new Decorator(new Girl()).show();}
}

装饰器类扩展了原对象的功能,像是一种包装,包装后更丰富了

在这里插入图片描述

更进一步

在上述化妆的例子上,更进一步,抽象出一个装饰器类,如下:

(装饰抽象类,Decorator)

/*** 装饰类*/
public abstract class Decorator implements Showable {private Showable showable;/*** 构造器注入*/public Decorator(Showable showable) {this.showable = showable;}@Overridepublic void show() {showable.show();}
}

(粉底类,继承装饰类,FoundationMakeup)

/*** 粉底类*/
public class FoundationMakeup extends Decorator {/*** 构造器注入*/public FoundationMakeup(Showable showable) {super(showable);}@Overridepublic void show() {System.out.print("抹上淡淡的粉底【");super.show();System.out.print("】");}
}

(口红类,继承装饰类,Lipstick)

/*** 口红类*/
public class Lipstick extends Decorator {/*** 构造器注入*/public Lipstick(Showable showable) {super(showable);}@Overridepublic void show() {System.out.print("抹上一层口红【");super.show();System.out.print("】");}
}

(客户端使用,Client,可以自由组合装饰方式)

public class Client {public static void main(String[] args) {// 搭配一new Lipstick(new FoundationMakeup(new Girl())).show();System.out.println();// 搭配二new FoundationMakeup(new Lipstick(new Girl())).show();}
}

运行如下:

在这里插入图片描述

JDK源码体现

装饰器模式,在JDK的IO流设计上有体现,如下:

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.zip.ZipInputStream;public class Client {public static void main(String[] args) throws FileNotFoundException {// 装饰器模式在Java源码的体现File file = new File("./src/main/java/structural/decorator/Client.java");ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(new FileInputStream(file)));}
}

扒一下源码,可见ZipInputStreamBufferedInputStreamFileInputStream都继承自抽象类InputStream,类比一下前面的化妆例子,InputStream也就是装饰抽象类。

  • ZipInputStream -> InflaterInputStream -> FilterInputStream -> InputStream

  • BufferedInputStream -> FilterInputStream -> InputStream

  • FileInputStream -> InputStream

与代理模式的区别

关于装饰器模式与代理模式的区别,这里介绍两本书中给的区别:

代理模式和装饰模式在实现时有些类似,但是代理模式主要是给真是主题类增加一些全新的职责,例如权限控制、缓冲处理、智能引用、远程访问等,这些职责与原有职责不属于同一个问题域。而装饰模式是通过装饰类为具体构件类增加一些相关的职责,是对原有职责的扩展,这些职责属于同一问题域。代理模式和装饰模式的目的也不相同,前者是控制对对象的访问,而后者是为对象动态地增加功能。
(引自《设计模式的艺术》刘伟著,第一版P201)


在《设计模式就该这样学》(P214)中,举了一个不错的例子:

简单来讲,假设现在想租房,那么势必会有一些事务发生:房源搜索、联系房东谈价格等。

假设按照代理模式进行思考,那么小明只需要找到一个房产中介,让他去做房源搜索、联系房东谈价格这些事情,小明只需要等待通知然后付中介费就行了。

而如果采用装饰器模式进行思考,因为装饰器模式强调的是自身功能扩展,也就是说,如果要找房子,小明自身就要增加房源搜索能力扩展、联系房东谈价格能力扩展,通过相应的装饰器,提升自身能力,一个人做完所有的事情。

我的理解,装饰器模式与代理模式都能解决问题,没有非装饰器模式能解决的问题,代理模式也是,区别在于解决问题的角度:从内到外,是装饰器模式,从外到内,是代理模式。

总结

本文介绍了结构型设计模式中的装饰器模式,参考《设计模式就该这样学》、《秒懂设计模式》、《设计模式的艺术》三本书,其中化妆的例子来自《秒懂设计模式》。


http://www.hkcw.cn/article/aQAbsedSYs.shtml

相关文章

交换机、路由器配置

四、交换机配置 1、以太网MAC地址 以太网地址用来识别一个以太网上的某个单独的设备或一组设备。 2、Ethernet II帧格式 3、交换机工作原理 初始状态 MAC地址学习(源MAC) 广播未知数据帧 接收方回应,交换机再次学习MAC地址 交换机实现单播…

业务系统-AI 智能导航设计-系统设计篇(上)

引言 在数字化转型加速推进的当下,企业业务系统正朝着复杂化、集成化方向快速发展。据 Gartner 调研数据显示,超过 68% 的企业业务系统因功能模块激增导致员工平均操作失误率上升 23%,传统菜单式导航与标准化培训模式已难以应对 "功能爆…

如何把电脑桌面设置在D盘?

一、桌面路径默认设置在C盘的问题 桌面路径默认设置在C盘的问题:如果你习惯于将重要文件存放在桌面上,那么在系统崩溃时,这些文件可能会遭受损失,因为只有重装系统才能解决问题。为了避免这种情况,你可以考虑将桌面路…

Mysql水平分表(基于Mycat)及常用分片规则

参考资料: 参考视频 参考博客 视频资料:链接: https://pan.baidu.com/s/1xT_WokN_xlRv0h06b6F3yg 提取码: aag3 Mysql分库分表(基于Mycat)的基本部署 MySQL垂直分库(基于MyCat) 概述: 本例是在垂直分库的基础上,又作的水平分库,参照前文也可以单独拿出来做水平分…

「Java教案」算术运算符与表达式

课程目标 1.知识目标 能够区分Java运算符的种类,例如,算术、赋值、关系、逻辑、位运算等。能够区分Java各类运算符的功能和使用场景。能够根据表达式的构成和计算规则,写出正确的表达式。能够根据运算符优先级与结合性&#xff…

普中STM32F103ZET6开发攻略(二)

接上文:普中STM32F103ZET6开发攻略(一)-CSDN博客 各位看官老爷们,点击关注不迷路哟。你的点赞、收藏,一键三连,是我持续更新的动力哟!!! 目录 接上文:普中…

FPGA仿真中阻塞赋值(=)和非阻塞赋值(<=)区别

FPGA仿真中阻塞赋值和非阻塞赋值的区别 单独仿真小模块对但将小模块加入整个工程仿真不对就有可能是没有注意到仿真中阻塞赋值和非阻塞赋值的区别 目录 前言 一、简介 二、设计实例 三、仿真实例 1、仿真用非阻塞赋值 2、仿真用阻塞赋值 总结 前言 网上很多人介绍verilo…

蓝云APP:云端存储,便捷管理

在数字化时代,数据的存储和管理变得尤为重要。无论是个人用户还是企业用户,都面临着海量数据的存储需求。蓝云APP正是这样一款为用户提供便捷、安全、高效的云存储服务的应用程序。它不仅提供了一种方便快捷的方式来管理和存储数据,还通过多种…

基于FPGA的VGA显示文字和动态数字基础例程,进而动态显示数据,类似温湿度等

基于FPGA的VGA显示文字和数字 前言一、VGA显示参数二、字模生成三、代码分析1.vga_char顶层2.vga_ctrl驱动文件3.vga_pic数据准备文件 总结 前言 结合正点原子以及野火的基础例程,理解了VGA本身基本协议,VGA本身显示像素为640*480,因此注意生…

低能硼注入的粒子控制 Axcelis Purion高电流离子注入机近晶圆环境中的石墨衬垫

低能硼注入的粒子控制 Axcelis Purion高电流离子注入机近晶圆环境中的石墨衬垫

自适应流量调度用于遥操作:面向时间敏感网络的通信与控制协同优化框架

英文标题:Adaptive Flow Scheduling for Teleoperation: A Communication and Control Co-Optimization Framework over Time-Sensitive Networks 中文标题:自适应流量调度用于遥操作:面向时间敏感网络的通信与控制协同优化框架 作者信息 …

PCIe-Error Detection(一)

下表为PCIe协议中给出的错误: 一、可纠正错误(Correctable Errors,8种)​​ ​​检错机制​​ ​​错误名称​​​​检测层级​​​​触发条件​​​​Receiver Error​​Physical接收端均衡器(EQ)监测到…

记忆解码 | 从神经机制到记忆逻辑的科学探索

注:本文为“记忆解码”相关文章合辑。 略作重排,未作探究。 要做的事情全忘了?这 2 种方法能拯救你的记忆力 环球科学 2024 年 07 月 29 日 22:00 北京 图片来源:Pixabay 作者 | Sarah Raskin 译者 | 郑添惺 审校 | clefable 你…

100V离线语音通断器

客户要求,需要能支持宽范围的离线语音通断器,具体需要能支持输入电压为100V左右直流。 找方案,重新做板,终于满足了客户需求,外壳为之前三路离线语音通断器,输出无源。 感谢客户,让我们的产品…

【中国企业数字化转型之路】企业的资源投入与数字化转型的产出效益平衡探索(下篇:完结)

在数字化转型的浪潮中,企业面临着前所未有的挑战与机遇。这一转型过程不仅需要大量的技术、人才、管理和时间投入,更需要在投入与产出之间找到精准的平衡点,以确保转型的效益最大化。技术投入方面,企业需斥巨资引进云计算、大数据、人工智能等先进技术,构建高效智能的数字…

【算法设计与分析】实验——二维0-1背包问题(算法分析题:算法思路),独立任务最优调度问题(算法实现题:实验过程,描述,小结)

说明:博主是大学生,有一门课是算法设计与分析,这是博主记录课程实验报告的内容,题目是老师给的,其他内容和代码均为原创,可以参考学习,转载和搬运需评论吱声并注明出处哦。 要求:3-…

6月2日星期一今日早报简报微语报早读

6月2日星期一,农历五月初七,早报#微语早读。 1、郑钦文晋级法网女单八强,刷新生涯法网最佳战绩; 2、中国汽车报:“价格战”是一场无休止的恶性循环,深陷其中者必将皆输; 3、四川成都市崇州市…

启动metastore时报错MetaException(message:Version information not found in metastore

把hdfs清空重新安装了一下&#xff0c;hive的mysql元数据库删除掉之后重建之后一直启动报错 metastore.RetryingHMSHandler (RetryingHMSHandler.java:<init>(83)) - HMSHandler Fatal error: MetaException(message:Version information not found in metastore.) 后来…

一元函数积分

1. 不同名函数积分 2.三角函数有理式

spring-boot接入websocket教程以及常见问题解决

我们使用spring-boot接入websocket有三种方式&#xff1a;使用EnableWebSocket、EnableWebSocketMessageBroker以及ServerEndpoint&#xff0c;本文主要介绍使用ServerEndpoint方式的流程以及碰到的问题解决 接入方式 添加依赖 确保spring-boot-starter-websocket依赖 <d…