当前位置: 首页 > 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;
}

总结

装饰模式看书的时候看的挺快的,但是想用自己的话写出来,还是得好好想想。
这篇博客对装饰模式做了一个自我理解的阐述,结合书中的例子进行分阶段设计,最后到代码的具体展现。
收获尚可。

http://www.lryc.cn/news/433345.html

相关文章:

  • 3.C_数据结构_栈
  • Debian11安装DolphinScheduler
  • C语言深度剖析--不定期更新的第五弹
  • python之事务
  • 文件加密软件都有哪些?推荐6款文件加密工具
  • Docker中的容器内部无法使用vi命令怎么办?
  • 【Linux系统编程】TCP实现--socket
  • 企业微信hook协议接口,聚合群聊客户管理工具开发
  • Selenium集成Sikuli基于图像识别的自动化测试
  • 【STM32实物】基于STM32设计的智能仓储管理系统(程序代码电路原理图实物图讲解视频设计文档等)——文末资料下载
  • libtool 中的 .la 文件说明
  • NLP-transformer学习:(6)dataset 加载与调用
  • 数据库系统 第43节 数据库复制
  • LabVIEW FIFO详解
  • 如何验证VMWare WorkStation的安装?
  • 论文阅读:AutoDIR Automatic All-in-One Image Restoration with Latent Diffusion
  • C++ | Leetcode C++题解之第392题判断子序列
  • 操作系统概述(三、虚拟化)
  • 基于ARM芯片与OpenCV的工业分拣机器人项目设计与实现流程详解
  • UNITY UI简易反向遮罩
  • 牛客周赛59(A,B,C,D,E二维循环移位,F范德蒙德卷积)
  • C语言中的隐型计算
  • ffmpeg面向对象-待定
  • 大厂嵌入式数字信号处理器(DSP)面试题及参考答案
  • GC-分代收集器
  • C++从入门到起飞之——priority_queue(优先级队列) 全方位剖析!
  • [数据集][目标检测]西红柿缺陷检测数据集VOC+YOLO格式17318张3类别
  • 【小沐学OpenGL】Ubuntu环境下glut的安装和使用
  • ROS 发行版 jazzy 加载urdf 渲染到 RVIZ2
  • SpringBoot中利用EasyExcel+aop实现一个通用Excel导出功能