设计模式学习[5]---装饰模式
文章目录
- 前言
- 1. 原理阐述
- 2. 举例
- 2.1 人装饰方案一
- 2.2 人装饰方案二
- 2.3 人装饰方案三
- 总结
前言
近期在给一个已有的功能拓展新功能时,基于原有的设计类图进行讨论。其中涉及到了装饰模式,因为书本很早已经看过一遍,所以谈及到这个名词的时候有点印象,只知道它是加功能用的,更细则的内容已经忘了。
这篇博客就是对装饰模式的一个复习。
1. 原理阐述
装饰模式:
动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
前半句话:一个类的设计在一开始并不会是非常完美的,虽然一开始做到了单一职责的原则,但是随着业务的扩大功能的不断开发,难免会出现多职责的情况。那么在后期添加新功能的时候,如果要保持原来类的核心职能尽可能的单一,而非和一些新加功能糅杂在一起,装饰模式就是解决这个问题的设计模式。
后半句话:我们可以给一个类派生子类,通过子类添加新功能。子类实际上还是依赖于父类,是is a的关系。增加新功能这个点,我们能不能想象成给人穿衣服的过程?将功能模块化,加不加功能,这个功能就在那,需要这个功能的时候,将功能和类进行绑定(装饰 )。衣服,人穿不穿它都在那(功能解耦),人穿就是装饰(绑定)。
上面的是我个人的理解,如有不对,留言指正。
2. 举例
以书中穿衣的例子为例,结合自己理解拓展。
2.1 人装饰方案一
把人比作一个类Person的对象,人穿衣服,其实就是一些函数操作。
那么简单一点的类图如下:

这个方案不合理。因为如果要增加新的装饰的话,就需要修改人这个类。
设计模式学习[3]—单一职责原则+开放封闭原则中我提到了开放封闭原则,那么我们修改人这个类,是不是违反了开放封闭原则?比如我添加穿袜子这个装饰操作,本质上它应该是对Person类的一个拓展,在开放封闭原则中,对于更改是封闭的,对于拓展是开放的。如果按照我们这个简单的类图来做,我们就需要修改Person类,就违反了开放封闭原则。
由此,我们考虑把这个装饰的过程抽象出来,在Person类中,用统一的一个接口去调用。
2.2 人装饰方案二
于是乎,就有了下面的类图。
这张类图里面,我们把人的装饰过程用形象展示这个接口包装起来。具体的装饰交给服饰类去处理。
这样我们要拓展,对于人这个类,其实没有改动。要拓展其实是对服饰类进行拓展。
我们这里通过面向对象的方式,将每一个装饰操作由具体的子类去负责。通过接口继承,多态实现。
现在我们思考一下这个服饰类和人类之间的关系。
回顾一下原理阐述,拓展新功能可以通过子类继承以及装饰模式,但是装饰模式更灵活(因为用的绑定)。
所以这里在类图的实际表现来说,服饰类其实应该是对人的一个实现。
在C++中,无论是继承还是实现,其实都是 实线——加△ 实线——加△ 实线——加△的画法。实现的方式在代码中是public继承,继承中就可以有public,protected,private几种继承的考量了,这里不深究。
2.3 人装饰方案三
知道了人和服饰类之间的关系,那么就有了下面的类图

从设计层面明白后,看一下具体代码.
对象的绑定关系其实是通过指针来实现的,服饰类的构造函数接受一个Person类的对象,作为绑定对象。后面的T恤类以及夹克类都是对这个绑定对象的一个装饰。
这里mian函数中出现的两种装饰方式,其实说明的是有些功能是有先后顺序的,比如先有数据接收功能再有数据处理功能,先收到数据才对数据进行处理。
#include <iostream>
#include <string>
class Person
{
public:Person() {};Person(std::string name){this->name = name;}virtual void Show(){std::cout << "装扮的" << this->name;}
private:std::string name;
};//服饰类
class Finery :public Person
{
protected:Person* component;public:void Decorate(Person* component){this->component = component;}void Show() override{if (component){component->Show();}}
};//服饰的具体类:T恤
class TShirts :public Finery
{
public:void Show() override{printf("T恤 "); Finery::Show();}
};//服饰的具体类:夹克
class Jacket :public Finery
{
public:void Show() override{printf("夹克 ");Finery::Show();}
};
int main()
{Person *cc = new Person("澄澈i");std::cout << "第一种装饰" << std::endl;TShirts* tshirt = new TShirts();Jacket* jacket = new Jacket();tshirt->Decorate(cc);jacket->Decorate(tshirt);jacket->Show();std::cout <<std::endl;std::cout << "第二种装饰" << std::endl;jacket->Decorate(cc);tshirt->Decorate(jacket);tshirt->Show();delete cc;delete tshirt;delete jacket;return 0;
}
总结
装饰模式看书的时候看的挺快的,但是想用自己的话写出来,还是得好好想想。
这篇博客对装饰模式做了一个自我理解的阐述,结合书中的例子进行分阶段设计,最后到代码的具体展现。
收获尚可。
相关文章:
设计模式学习[5]---装饰模式
文章目录 前言1. 原理阐述2. 举例2.1 人装饰方案一2.2 人装饰方案二2.3 人装饰方案三 总结 前言 近期在给一个已有的功能拓展新功能时,基于原有的设计类图进行讨论。其中涉及到了装饰模式,因为书本很早已经看过一遍,所以谈及到这个名词的时候…...
3.C_数据结构_栈
概述 什么是栈: 栈又称堆栈,是限定在一段进行插入和删除操作的线性表。具有后进先出(LIFO)的特点。 相关名词: 栈顶:允许操作的一端栈底:不允许操作的一端空栈:没有元素的栈 栈的作用: 可…...
Debian11安装DolphinScheduler
安装地址 前置准备工作 JDK安装 下载JDK (1.8),安装并配置 JAVA_HOME 环境变量,并将其下的 bin 目录追加到 PATH 环境变量中。如果你的环境中已存在,可以跳过这步 二进制包安装DolphinScheduler 依赖 apt-get install psmisc 二进制安…...
C语言深度剖析--不定期更新的第五弹
const关键字 来看一段代码: #include <stdio.h> int main() {int a 10;a 20;printf("%d\n", a);return 0; }运行结果如下: 接下来我们在上面的代码做小小的修改: #include <stdio.h> int main() {const int a 1…...
python之事务
事务(Transaction)是数据库管理系统(DBMS)中的一个重要概念,用于确保一组数据库操作要么全部成功,要么全部失败,从而保证数据的一致性和完整性。 事务ACID 特性 事务具有以下四个特性…...
文件加密软件都有哪些?推荐6款文件加密工具
不久前,一家知名科技公司的内部文件在未经授权的情况下被泄露到了网络上,其中包括了公司的核心技术蓝图、客户名单及未来战略规划。这一事件不仅给公司带来了巨大的经济损失,还严重损害了企业的声誉。 如何防止以上事件的发生呢,文…...
Docker中的容器内部无法使用vi命令怎么办?
不知道你是否遇到过,在修改容器内部的配置的时候,有时候会提示vi命令不可用。尝试去安装vi插件,好像也不是很容易,有什么办法可以帮助我们修改这个配置文件呢? 解决办法 这时候,我们就需要用到docker cp 命令了,它可以帮助我们把容器内部的文件复制到宿主机上,也可以将…...
【Linux系统编程】TCP实现--socket
使用套接字socket实现服务器和客户端之间的TCP通信。 流程如下: 实现代码: /* server.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <s…...
企业微信hook协议接口,聚合群聊客户管理工具开发
服务提供了丰富的API和SDK,可以在企微的功能之上进行应用开发和功能扩展 自建应用可以调用企微hook或协议提供的接口来实现数据交互,可以直接调用hook或协议接口提供的功能来进行消息的发送与接收、用户管理、应用管理等操作,通过接口可以实…...
Selenium集成Sikuli基于图像识别的自动化测试
看起来您提供了一个链接,但目前我并没有从该链接获取到具体的信息内容。不过,如果您希望了解如何将Sikuli集成到Selenium中,我可以为您提供一些基本的指南。 什么是Sikuli? Sikuli是一款开源工具,用于基于图像识别的自动化测试。它可以识别屏幕上的图像,并模拟用户的交…...
【STM32实物】基于STM32设计的智能仓储管理系统(程序代码电路原理图实物图讲解视频设计文档等)——文末资料下载
基于STM32设计的智能仓储管理系统 演示视频: 基于STM32设计的智能仓储管理系统 摘要 近年来,随着我国仓储发展的和药品需求的不断增多,许多医院都采用药物仓储管理系统。我国的药物仓储产业已经有了长足的发展,仓库的规模不断变大,对仓储的要求也不断增高,药物的存储,…...
libtool 中的 .la 文件说明
libtool 中的 .la 文件说明 1 概述 在 Linux 系统中,libtool 是一个用于自动化编译和链接复杂软件项目的工具,特别是那些使用了共享库(.so 文件在 Linux 上,.dylib 在 macOS 上)的项目。它帮助处理各种编译器和链接器…...
NLP-transformer学习:(6)dataset 加载与调用
NLP-transformer学习:(6)dataset 加载与调用 平常其实也经常进行trainning等等,但是觉得还是觉得要补补基础,所以静下心,搞搞基础联系 本章节基于 NLP-transformer学习:(5࿰…...
数据库系统 第43节 数据库复制
数据库复制是一种重要的技术,用于在多个数据库系统之间同步数据。这在分布式系统中尤其重要,因为它可以提高数据的可用性、可扩展性和容错性。以下是几种常见的数据库复制类型: 主从复制 (Master-Slave Replication): 在这种模式下࿰…...
LabVIEW FIFO详解
在LabVIEW的FPGA开发中,FIFO(先入先出队列)是常用的数据传输机制。通过配置FIFO的属性,工程师可以在FPGA和主机之间,或不同FPGA VIs之间进行高效的数据传输。根据具体需求,FIFO有多种类型与实现方式&#x…...
如何验证VMWare WorkStation的安装?
如何验证VMWare WorkStation的安装? 右击"网络",点击 打开"网络和Internet设置",点击更改适配器选项,如果出现VMNet1和VMNet8,则说明安装成功。...
论文阅读:AutoDIR Automatic All-in-One Image Restoration with Latent Diffusion
论文阅读:AutoDIR: Automatic All-in-One Image Restoration with Latent Diffusion 这是 ECCV 2024 的一篇文章,利用扩散模型实现图像恢复的任务。 Abstract 这篇文章提出了一个创新的 all-in-one 的图像恢复框架,融合了隐扩散技术&#x…...
C++ | Leetcode C++题解之第392题判断子序列
题目: 题解: class Solution { public:bool isSubsequence(string s, string t) {int n s.size(), m t.size();vector<vector<int> > f(m 1, vector<int>(26, 0));for (int i 0; i < 26; i) {f[m][i] m;}for (int i m - 1; …...
操作系统概述(三、虚拟化)
系列文章目录 文章目录 系列文章目录前言十一、操作系统上的进程1. 从系统启动到第一个进程系统调用:fork(), 创建进程execv()PATH环境变量销毁进程 十二、进程的地址空间**查看进程的地址空间**进程地址空间管理进程地址空间隔离 十三、系统调用和 shell十四、C标准…...
基于ARM芯片与OpenCV的工业分拣机器人项目设计与实现流程详解
一、项目概述 项目目标和用途 本项目旨在设计和实现一套工业分拣机器人系统,能够高效、准确地对不同类型的物品进行自动分拣。该系统广泛应用于物流、仓储和制造业,能够显著提高工作效率,降低人工成本。 技术栈关键词 ARM芯片 步进电机控…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!
目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...
深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙
WebGL:在浏览器中解锁3D世界的魔法钥匙 引言:网页的边界正在消失 在数字化浪潮的推动下,网页早已不再是静态信息的展示窗口。如今,我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室,甚至沉浸式的V…...
ThreadLocal 源码
ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...
数据分析六部曲?
引言 上一章我们说到了数据分析六部曲,何谓六部曲呢? 其实啊,数据分析没那么难,只要掌握了下面这六个步骤,也就是数据分析六部曲,就算你是个啥都不懂的小白,也能慢慢上手做数据分析啦。 第一…...
大模型——基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程 下载安装Docker Docker官网:https://www.docker.com/ 自定义Docker安装路径 Docker默认安装在C盘,大小大概2.9G,做这行最忌讳的就是安装软件全装C盘,所以我调整了下安装路径。 新建安装目录:E:\MyS…...
Java多线程实现之Runnable接口深度解析
Java多线程实现之Runnable接口深度解析 一、Runnable接口概述1.1 接口定义1.2 与Thread类的关系1.3 使用Runnable接口的优势 二、Runnable接口的基本实现方式2.1 传统方式实现Runnable接口2.2 使用匿名内部类实现Runnable接口2.3 使用Lambda表达式实现Runnable接口 三、Runnabl…...
