设计模式——装饰器模式
装饰器模式
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
装饰器模式通过将对象包装在装饰器类中,以便动态地修改其行为。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
我们通过下面的实例来演示装饰器模式的用法。其中,我们将把一个形状装饰上不同的颜色,同时又不改变形状类。
优缺点
优点
- 不改动原有代码,动态增加功能。
- 对象间不会相互依赖、松耦合。
- 符合开闭原则,扩展性好,便于维护。
缺点
- 装饰器环节过多的话,导致装饰器类膨胀。
- 装饰器层层嵌套比较复杂,可能导致排查问题流程繁琐。
装饰器模式的结构
通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰器模式的目标。下面来分析其基本结构和实现方法。
模式的结构
装饰器模式主要包含以下角色。
- 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
- 具体构件(ConcreteComponent)角色:实现抽象构件,通过装饰角色为其添加一些职责。
- 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
装饰器模式的结构图如图所示。

装饰器模式实例:
实例——图画
不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
代码如下:
画(Painting接口)
public interface Painting {public void show();
}
唐宫仕女图(TangGong类)
public class TangGong implements Painting {@Overridepublic void show(){System.out.println("这是一副唐宫仕女图");}
}
装饰器类
public class Decorator implements Painting {private Painting painting;public Decorator(Painting monaLisa){this.painting = monaLisa;}@Overridepublic void show() {System.out.println("先加上相框");painting.show();System.out.println("再扣上玻璃");}
}
测试类
public class DecoratorTest {public static void main(String[] args) {Painting painting = new TangGong();Painting monaLisa = new Decorator(painting);TangGong.show();}
}
实现方式 ——蜜雪冰城奶茶
秋天到了,女朋友非要喝秋天的第一杯奶茶,到了“蜜雪冰城”奶茶店后,给女朋友点了一杯奶茶,加了珍珠、芒果等配料,给自己点了一杯加冰柠檬水,加了冰块、柠檬片等配料,这时候就可以使用装饰器模式。
奶茶:抽象构件
珍珠芒果奶茶、柠檬水:具体构件
配料:装饰角色
珍珠、芒果、柠檬:具体装饰角色
代码实现:
抽象构件(Component)角色:奶茶
public interface IMilktea {void addDosing();
}
具体构件(ConcreteComponent)角色:珍珠奶茶
public class PearlMilktea implements IMilktea{@Overridepublic void addDosing() {System.out.println("开始制作:珍珠奶茶");}
}
柠檬水
public class LemonMilktea implements IMilktea{@Overridepublic void addDosing() {System.out.println("开始制作:柠檬水");}
}
装饰(Decorator)角色:配料
public abstract class Dosing implements IMilktea{IMilktea iMilktea;public Dosing(IMilktea iMilktea){this.iMilktea = iMilktea;}@Overridepublic void addDosing() {this.iMilktea.addDosing();}
}
具体装饰(ConcreteDecorator)角色:
加珍珠
public class Pearl extends Dosing {public Pearl(IMilktea iMilktea) {super(iMilktea);}@Overridepublic void addDosing() {super.addDosing();System.out.println("制作中:加珍珠");}
}
加芒果
public class Mango extends Dosing {public Mango(IMilktea iMilktea) {super(iMilktea);}@Overridepublic void addDosing() {super.addDosing();System.out.println("制作中:加芒果");}
}
加柠檬
public class Lemon extends Dosing {public Lemon(IMilktea iMilktea) {super(iMilktea);}@Overridepublic void addDosing() {super.addDosing();System.out.println("制作中:加柠檬");}
}
加冰
public class Ice extends Dosing {public Ice(IMilktea iMilktea) {super(iMilktea);}@Overridepublic void addDosing() {super.addDosing();System.out.println("制作中:加冰");}
}
客户端
public class Client {public static void main(String[] args) {System.out.println("服务员:你好,需要点什么呀?");System.out.println("我: 一杯加芒果、加珍珠的珍珠奶茶,一杯加柠檬、加冰的柠檬水");System.out.println("服务员:好的。");PearlMilktea pearlMilktea = new PearlMilktea();Pearl pearl = new Pearl(pearlMilktea);Mango mango = new Mango(pearl);Ice ice = new Ice(mango);ice.addDosing();System.out.println("第一杯制作完成");LemonMilktea lemonMilktea = new LemonMilktea();Lemon lemon = new Lemon(lemonMilktea);Ice ice1 = new Ice(lemon);ice1.addDosing();System.out.println("第二杯制作完成");System.out.println("我:珍珠奶茶怎么加冰了?");System.out.println("服务员:对不起,珍珠奶茶做错了,重新给您做。");mango.addDosing();System.out.println("不加冰的珍珠奶茶制作完成");System.out.println("我:好的,谢谢!");}
}
输出结果
服务员:你好,需要点什么呀?
我: 一杯加芒果、加珍珠的珍珠奶茶,一杯加柠檬、加冰的柠檬水
服务员:好的。
开始制作:珍珠奶茶
制作中:加珍珠
制作中:加芒果
制作中:加冰
第一杯制作完成
开始制作:柠檬水
制作中:加柠檬
制作中:加冰
第二杯制作完成
我:珍珠奶茶怎么加冰了?
服务员:对不起,珍珠奶茶做错了,重新给您做。
开始制作:珍珠奶茶
制作中:加珍珠
制作中:加芒果
不加冰的珍珠奶茶制作完成
我:好的,谢谢!
到此,女朋友喝到了秋天的第一杯奶茶。
应用场景
- 动态的增加对象的功能;
- 不能以派生子类的方式来扩展功能;
- 限制对象的执行条件;
- 参数控制和检查等;
相关文章:
设计模式——装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 装饰器模式通过将对象包装在装饰器类中,以便动态…...
①matlab的命令掌握
目录 输入命令 命名变量 保存和加载变量 使用内置的函数和常量 输入命令 1.您可以通过在命令行窗口中 MATLAB 提示符 (>>) 后输入命令 任务 使用命令 3*5 将数值 3 和 5 相乘。 答案 3*5 2.除非另有指定,否则 MATLAB 会将计算结果存储在一个名为 ans…...
MySQL----索引
一、索引的概念 索引是一个排序的列表,在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址(类似于c语言的链表通过指针指向数据记录的内存地址)。使用索引后可以不用扫描全表来定位某行的数据,而是先通过索引表找到该…...
秒杀系统的业务流程以及优化方案(实现异步秒杀)
先看基本的业务流程 那么我们可以看到整个流程都是一个线程来完成的,这样的话耗时还是很长的,那么可不可以采用多线程去实现呢? 首先我们要思考怎么对业务进行拆分,可以想象一个我们去饭店点餐,会有前台接待ÿ…...
Java实现根据商品ID获取1688商品详情跨境属性数据,1688商品重量数据接口,1688API接口封装方法
要通过1688的API获取商品详情跨境属性数据,您可以使用1688开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例,展示如何通过1688开放平台API获取商品详情属性数据接口: 首先,确保您已注册成为1688开放平台的开发者…...
前端面试的性能优化部分(14)每天10个小知识点
目录 系列文章目录前端面试的性能优化部分(1)每天10个小知识点前端面试的性能优化部分(2)每天10个小知识点前端面试的性能优化部分(3)每天10个小知识点前端面试的性能优化部分(4)每天…...
Uniapp笔记(六)uniapp基础
一、腾讯地图 1、uniapp地图渲染 <template><view><map class"map" :longitude"longitude" :latitude"latitude"></map></view> </template> <script>export default {data() {return {longitude:1…...
C++ sort函数用法
sort函数是C标准库中的一个排序算法,头文件是algorithm,用于对容器中的元素进行排序。它可以对任何可排序的容器(如数组、向量、列表等)进行排序。 有以下四个基本用法: 1. 自定义排序规则:可以通过提供自…...
电子仓库预测水浸事件,他怎么做到的?
仓库环境中水浸事件可能导致严重的损失,不仅对货物造成损害,还可能影响设备的正常运行甚至威胁安全。 因此,为了应对这一挑战,引入一套完善的仓库水浸监控系统成为了不可或缺的措施。 客户案例 广东某电子公司是一家领先的电子设…...
CMake调用第三方库的两种方法
为了让连接器搜索到库路径,一般有两种方法 link_directories命令 使用步骤## 在add_executable或add_library前引入第三方库 # 1.引入第三方库,${THIRD_PARTY_PREFIX}为用户定义的第三方库目录 link_directories(${THIRD_PARTY_PREFIX}/lib) # 2.增加第三方库头文…...
Django基础7——用户认证系统、Session管理、CSRF安全防护机制
文章目录 一、用户认证系统二、案例:登陆认证2.1 平台登入2.2 平台登出2.3 login_required装饰器 三、Django Session管理3.1 Django使用Session3.1.1 Cookie用法3.1.2 Session用法 3.2 案例:用户登录认证 四、Django CSRF安全防护机制 一、用户认证系统…...
基于流计算 Oceanus(Flink) CDC 做好数据集成场景
由于第一次做实时,所以踩坑比较多,见谅(测试环境用的flink),小公司没有用到hadoop组件 一、踩坑记录 1:本地代码的flink版本是flink1.15.4,生产环境是flink1.16.1,在使用侧输出流时报错,需要使用以下写法,需要使用Si…...
MySQL8.Xx安装控制台未生成随机密码解决方案
MySQL8.xx一主两从复制安装与配置 MySQL8.XX随未生成随机密码解决方案 MySQL8.0.30一主两从复制与配置(一) 一: Mysql 安装时控制台未生成密码 安装过程中解压或者安装时报错等,这种情况一般是因网络等其他原因导致下载的安装包不完整, 重新下载安装即可; 二:…...
安装VS2005时提示:请插入磁盘:visual studio 2005 DVD
安装VS2005时提示:请插入磁盘:visual studio 2005 DVD 修改卷标为 "DVD1"...
OpenVINO2023使用简介
1 下载安装 先在anaconda中创建一个虚拟环境,该环境的python版本为3.7,之所以使用python3.7,是因为我在3.9上安装过程中出现不少bug,后面新建了一个3.7的环境才解决,我不知道是否由于和我已有环境中某些包不兼容&…...
基于React实现无限滚动的日历详细教程,附源码【手写日历教程第二篇】
前言 最常见的日历大部分都是滚动去加载更多的月份,而不是让用户手动点击按钮切换日历月份。滚动加载的交互方式对于用户而言是更加丝滑和舒适的,没有明显的操作割裂感。 那么现在需要做一个这样的无限滚动的日历,前端开发者应该如何去思考…...
68、使用aws官方的demo和配置aws服务,进行视频流上传播放
基本思想:参考官方视频,进行了配置aws,测试了视频推流,rtsp和mp4格式的视频貌似有问题,待调研和解决 第一步:1) 进入aws的网站,然后进入ioT Core 2)先配置 Thing types & Thing,选择香港的节点,然后AWS ioT--->Manage---> Thing type 然后输入名字,创建Th…...
数据库
表 记录:行 字段(属性): 列 以行列的形式就组成了表(数据存储在表中) 关系数据库的表由记录组成,记录由字段组成,字段由字符或数字组成。它可以供各种用户共享, 具有最小冗余度和较高…...
深入了解fcntl函数:Linux系统编程中的文件控制
文章目录 概述介绍函数原型与参数 拓展:fcntl改文件属性总结 概述 摘要: fcntl函数是Linux系统编程中一个重要的函数,用于对文件描述符进行各种控制操作。本文将详细介绍fcntl函数的原型、各个参数的用法,以及阻塞和非阻塞模式切换的方法&am…...
汇川技术内推码
[庆祝]不一样的内推码[庆祝]:IVSM2R 投递了可以评论下名字,我会帮忙留意进度。 汇尔成川,共赴星海,欢迎加入,职等你来。 嵌入式软硬件,机器人算法,电机控制,通信软件,PLC…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
(转)什么是DockerCompose?它有什么作用?
一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用,而无需手动一个个创建和运行容器。 Compose文件是一个文本文件,通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
