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

设计模式学习[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 人装饰方案三 总结 前言 近期在给一个已有的功能拓展新功能时&#xff0c;基于原有的设计类图进行讨论。其中涉及到了装饰模式&#xff0c;因为书本很早已经看过一遍&#xff0c;所以谈及到这个名词的时候…...

3.C_数据结构_栈

概述 什么是栈&#xff1a; 栈又称堆栈&#xff0c;是限定在一段进行插入和删除操作的线性表。具有后进先出(LIFO)的特点。 相关名词&#xff1a; 栈顶&#xff1a;允许操作的一端栈底&#xff1a;不允许操作的一端空栈&#xff1a;没有元素的栈 栈的作用&#xff1a; 可…...

Debian11安装DolphinScheduler

安装地址 前置准备工作 JDK安装 下载JDK (1.8)&#xff0c;安装并配置 JAVA_HOME 环境变量&#xff0c;并将其下的 bin 目录追加到 PATH 环境变量中。如果你的环境中已存在&#xff0c;可以跳过这步 二进制包安装DolphinScheduler 依赖 apt-get install psmisc 二进制安…...

C语言深度剖析--不定期更新的第五弹

const关键字 来看一段代码&#xff1a; #include <stdio.h> int main() {int a 10;a 20;printf("%d\n", a);return 0; }运行结果如下&#xff1a; 接下来我们在上面的代码做小小的修改&#xff1a; #include <stdio.h> int main() {const int a 1…...

python之事务

事务&#xff08;Transaction&#xff09;是数据库管理系统&#xff08;DBMS&#xff09;中的一个重要概念&#xff0c;用于确保一组数据库操作要么全部成功&#xff0c;要么全部失败&#xff0c;从而保证数据的一致性和完整性。 事务ACID 特性 事务具有以下四个特性&#xf…...

文件加密软件都有哪些?推荐6款文件加密工具

不久前&#xff0c;一家知名科技公司的内部文件在未经授权的情况下被泄露到了网络上&#xff0c;其中包括了公司的核心技术蓝图、客户名单及未来战略规划。这一事件不仅给公司带来了巨大的经济损失&#xff0c;还严重损害了企业的声誉。 如何防止以上事件的发生呢&#xff0c;文…...

Docker中的容器内部无法使用vi命令怎么办?

不知道你是否遇到过,在修改容器内部的配置的时候,有时候会提示vi命令不可用。尝试去安装vi插件,好像也不是很容易,有什么办法可以帮助我们修改这个配置文件呢? 解决办法 这时候,我们就需要用到docker cp 命令了,它可以帮助我们把容器内部的文件复制到宿主机上,也可以将…...

【Linux系统编程】TCP实现--socket

使用套接字socket实现服务器和客户端之间的TCP通信。 流程如下&#xff1a; 实现代码&#xff1a; /* server.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <arpa/inet.h> #include <s…...

企业微信hook协议接口,聚合群聊客户管理工具开发

服务提供了丰富的API和SDK&#xff0c;可以在企微的功能之上进行应用开发和功能扩展 自建应用可以调用企微hook或协议提供的接口来实现数据交互&#xff0c;可以直接调用hook或协议接口提供的功能来进行消息的发送与接收、用户管理、应用管理等操作&#xff0c;通过接口可以实…...

Selenium集成Sikuli基于图像识别的自动化测试

看起来您提供了一个链接,但目前我并没有从该链接获取到具体的信息内容。不过,如果您希望了解如何将Sikuli集成到Selenium中,我可以为您提供一些基本的指南。 什么是Sikuli? Sikuli是一款开源工具,用于基于图像识别的自动化测试。它可以识别屏幕上的图像,并模拟用户的交…...

【STM32实物】基于STM32设计的智能仓储管理系统(程序代码电路原理图实物图讲解视频设计文档等)——文末资料下载

基于STM32设计的智能仓储管理系统 演示视频: 基于STM32设计的智能仓储管理系统 摘要 近年来,随着我国仓储发展的和药品需求的不断增多,许多医院都采用药物仓储管理系统。我国的药物仓储产业已经有了长足的发展,仓库的规模不断变大,对仓储的要求也不断增高,药物的存储,…...

libtool 中的 .la 文件说明

libtool 中的 .la 文件说明 1 概述 在 Linux 系统中&#xff0c;libtool 是一个用于自动化编译和链接复杂软件项目的工具&#xff0c;特别是那些使用了共享库&#xff08;.so 文件在 Linux 上&#xff0c;.dylib 在 macOS 上&#xff09;的项目。它帮助处理各种编译器和链接器…...

NLP-transformer学习:(6)dataset 加载与调用

NLP-transformer学习&#xff1a;&#xff08;6&#xff09;dataset 加载与调用 平常其实也经常进行trainning等等&#xff0c;但是觉得还是觉得要补补基础&#xff0c;所以静下心&#xff0c;搞搞基础联系 本章节基于 NLP-transformer学习&#xff1a;&#xff08;5&#xff0…...

数据库系统 第43节 数据库复制

数据库复制是一种重要的技术&#xff0c;用于在多个数据库系统之间同步数据。这在分布式系统中尤其重要&#xff0c;因为它可以提高数据的可用性、可扩展性和容错性。以下是几种常见的数据库复制类型&#xff1a; 主从复制 (Master-Slave Replication): 在这种模式下&#xff0…...

LabVIEW FIFO详解

在LabVIEW的FPGA开发中&#xff0c;FIFO&#xff08;先入先出队列&#xff09;是常用的数据传输机制。通过配置FIFO的属性&#xff0c;工程师可以在FPGA和主机之间&#xff0c;或不同FPGA VIs之间进行高效的数据传输。根据具体需求&#xff0c;FIFO有多种类型与实现方式&#x…...

如何验证VMWare WorkStation的安装?

如何验证VMWare WorkStation的安装&#xff1f; 右击"网络"&#xff0c;点击 打开"网络和Internet设置"&#xff0c;点击更改适配器选项&#xff0c;如果出现VMNet1和VMNet8&#xff0c;则说明安装成功。...

论文阅读:AutoDIR Automatic All-in-One Image Restoration with Latent Diffusion

论文阅读&#xff1a;AutoDIR: Automatic All-in-One Image Restoration with Latent Diffusion 这是 ECCV 2024 的一篇文章&#xff0c;利用扩散模型实现图像恢复的任务。 Abstract 这篇文章提出了一个创新的 all-in-one 的图像恢复框架&#xff0c;融合了隐扩散技术&#x…...

C++ | Leetcode C++题解之第392题判断子序列

题目&#xff1a; 题解&#xff1a; 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. 从系统启动到第一个进程系统调用&#xff1a;fork(), 创建进程execv()PATH环境变量销毁进程 十二、进程的地址空间**查看进程的地址空间**进程地址空间管理进程地址空间隔离 十三、系统调用和 shell十四、C标准…...

基于ARM芯片与OpenCV的工业分拣机器人项目设计与实现流程详解

一、项目概述 项目目标和用途 本项目旨在设计和实现一套工业分拣机器人系统&#xff0c;能够高效、准确地对不同类型的物品进行自动分拣。该系统广泛应用于物流、仓储和制造业&#xff0c;能够显著提高工作效率&#xff0c;降低人工成本。 技术栈关键词 ARM芯片 步进电机控…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN&#xff0c;根据VPN原理&#xff0c;打通两个内网必然需要借助一个公共中继节点&#xff0c;ktconnect工具巧妙的利用k8s原生的portforward能力&#xff0c;简化了建立连接的过程&#xff0c;apiserver间接起到了中继节…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...