一、简介

1、什么是装饰器模式

装饰器模式是结构型设计模式。

装饰器是现有类的一个包装,可以在不修改现有类且不增加子类的情况下扩展现有类。

【注】可以实现向一个现有对象添加新的功能,同时又不改变其结构的设计模式,称为结构型模式。

2、为什么使用装饰器模式

装饰器模式用于需要对现有类进行扩展的场景。

一般情况下,我们想要扩展现有类还可以声明它的子类,即使用继承的特性达到目的。但是如果我们经常使用增加子类的方法扩展现有类,会造成子类的臃肿膨胀。

二、装饰器模式实例

博主最近沉迷在某视频软件上看房车旅行相关的小视频。我们以房车做个例子。

假设某房车生产厂家提供A型房车和C型房车两款房车。两款房车都有各自的一些出厂自带的基础功能。但厂家也给客户提供额外加装的一些功能(假设提供额外加装太阳能电池板和额外加装户外燃气灶台),客户可以根据自己的需要自定义自己的爱车。

在这个工程中,我们使用装饰者模式需要下面几个组件(类):

1)房车产品抽象类RVCar;

2)A型房车具体类A_RVCar;

3)C型房车具体类C_RVCar;

4)房车装饰者抽象类ExtraDecorator;

5)太阳能电池板具体类SolarPanel;

6)户外灶台具体类OutDoorCookTop;

代码实现

1)房车抽象类RVCar

//房车类
class RVCar
{
public:RVCar() {}virtual ~RVCar() {}virtual void ShowFeatures() = 0;
};

2)A型房车具体类,继承类RVCar,具有A型房车出厂自带的基础功能。可以提供A型房车实例。

//具体房车类
class A_RVCar : public RVCar
{
public:void ShowFeatures(){cout << "这是一辆A型房车" << endl;}
};

3)C型房车具体类,继承类RVCar,具有C型房车出厂自带的基础功能。可以提供C型房车实例。

//具体房车类
class C_RVCar : public RVCar
{
public:void ShowFeatures(){cout << "这是一辆C型房车" << endl;}
};

4)房车装饰者抽象类ExtraDecorator,继承RVCar;

//额外装修的抽象基类
class ExtraDecorator : public RVCar
{
public:ExtraDecorator(RVCar* car) : _car(car) {}virtual ~ExtraDecorator() {}virtual void ShowFeatures(){if (nullptr != _car){_car->ShowFeatures();}}private:RVCar* _car;
};

5)太阳能电池板具体类SolarPanel,继承类ExtraDecorator,提供给某一辆房车(传入的房车对象指针)加装太阳能电池板的服务,即可以实例化一辆具有太阳能电池板的某型房车。

//太阳能电池板类
class SolarPanel : public ExtraDecorator
{
public:SolarPanel(RVCar* car) : ExtraDecorator(car) {}virtual void ShowFeatures(){ExtraDecorator::ShowFeatures();setSolarPanel();}private:void setSolarPanel(){cout << "安装了太阳能电池板!房车增加了功能:用太阳能发电!" << endl;}
};

6)户外灶台具体类SolarPanel,继承类ExtraDecorator,提供给某一辆房车(传入的房车对象指针)加装户外灶台的服务,即可以实例化一辆具有户外灶台的某型房车。

//户外灶台类
class OutDoorCookTop : public ExtraDecorator
{
public:OutDoorCookTop(RVCar* car) : ExtraDecorator(car) {}virtual void ShowFeatures(){ExtraDecorator::ShowFeatures();setOutDoorCookTop();}private:void setOutDoorCookTop(){cout << "安装了户外灶台!房车增加了功能:户外做饭!" << endl;}
};

7)客户“买车”,厂家根据客户需求提供车辆

int main()
{//aCar为一辆基础款A型房车RVCar* aCar = new A_RVCar();aCar->ShowFeatures();cout << endl;//outCookACar为一辆加装了户外灶台的C型房车RVCar* outCookACar = new OutDoorCookTop(new C_RVCar());outCookACar->ShowFeatures();system("pause");return 0;
}

【注】为了区别其他结构型设计模式,理解装饰器模式的特征,我根据自己的理解总结几点:

1、装饰器模式的作用是为了生成符合额外增加的功能的对象,所以上述实例中的ExtraDecorator类需要继承RVCar,因为经过装饰的具体对象还是一辆房车,需要给客户返回RVCar的对象指针;

所以我认为一些文章中类似这种使用是不正确的,如果这样使用,为什么还要继承RVCar呢?

//一辆加装了户外灶台的C型房车
ExtraDecorator* outCookACar = new OutDoorCookTop(new C_RVCar());
outCookACar->ShowFeatures();

2、这里解释一下为什么使用装饰器模式而不是扩展子类的方法实现工程。假设使用扩展子类的方法实现这个工程,则我们在上面装饰器组件1)2)3)的基础上还需要:

4)加装太阳能电池板的A型房车,继承类A,用于扩展类A的功能;

5)加装户外燃气灶的A型房车,继承类A,用于扩展类A的功能;

6)加装太阳能电池板的C型房车,继承类C,用于扩展类C的功能;

7)加装户外燃气灶的C型房车,继承类C,用于扩展类C的功能;

可见,厂家如果提供M个额外加装服务,有N个基础车型,想要实现加装服务-车型自由组合。扩展子类法需要扩展M*N个子类,可见十分的不灵活,会造成大量的子类膨胀。而使用装饰者模式则有几种额外服务,则增加几个装饰者子类,有几种车型,则增加几种房车具体类,即只需要扩展M+N个类,需要实例化时灵活“组装”即可。

设计模式-装饰器模式 C++相关推荐

  1. Python设计模式-装饰器模式

    Python设计模式-装饰器模式 代码基于3.5.2,代码如下; #coding:utf-8 #装饰器模式class Beverage():name = ""price = 0.0 ...

  2. Go 设计模式 - 装饰器模式

    装饰模式使用对象组合的方式动态改变或增加对象行为.Go语言借助于匿名组合和非入侵式接口可以很方便实现装饰模式.使用匿名组合,在装饰器中不必显式定义转调原对象方法. 设计模式 装饰器模式 装饰器模式主要 ...

  3. Spring设计模式(装饰器模式)

    Spring设计模式(装饰器模式) 模式的定义: 装饰者模式定义: ​ 动态地为一个对象添加一些额外的职责,若要扩展一个对象的功能,装饰者提供了比继承更有弹性的替代方案. 模式的结构图 : 模式包含角 ...

  4. Java设计模式-装饰器模式 理论代码相结合

    继Java设计模式适配器模式后的装饰器模式来啦,让我们一起看看吧. 会了就当复习丫,不会来一起来看看吧. 很喜欢一句话:"八小时内谋生活,八小时外谋发展". 如果你也喜欢,让我们一 ...

  5. 设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.简单来说,装饰器模式就是 ...

  6. PHP设计模式——装饰器模式

    声明:本系列博客参考资料<大话设计模式>,作者程杰. 装饰器模式又叫装饰者模式.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装 ...

  7. 设计模式---装饰器模式(C++实现)

    装饰器模式(Decorator Pattern)允许向一个现有对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原 ...

  8. C++设计模式 装饰器模式

    文章目录 1. 先验知识 2. 装饰器模式相关概念 3. 装饰器模式的应用 3.1 应用1: 给形状添加新的特征 不同形状加红 3.2 应用2: 给一个人穿不同的衣服 a 直接person类, 增加穿 ...

  9. 白话设计模式-装饰器模式的使用和意义

    装饰器模式展示 在学习设计模式的过程中,将自己对于设计模式的理解,以最简单,最白话的方式,分享给大家.个人觉得,对于设计模式的理解,需要将他从最抽象的理论里,真实的代入到实际的业务场景中,将会有最深刻 ...

最新文章

  1. 找出文件1中有而文件2中没有的数据
  2. zoj 3627(贪心)
  3. smarty半小时快速上手教程
  4. 多个局域网共享DHCP服务器
  5. 鼠标放到控件上 DIV悬浮提示效果(四种)
  6. 李彦宏:百度吹过的牛逼今天实现了!
  7. 国外的电子商务开发情况
  8. style 字体加粗_第9篇 Qt Quick入门教程之基础(九)文本显示和字体
  9. mysql触发器trigger 实例详解
  10. 指数函数以及对数函数的导数
  11. 贝壳找房原生爬虫租房分析
  12. 51单片机汇编学习例程(6)——74HC573数码管篇
  13. java程序cpu突然飚高_fullGC 频繁导致CPU飙高
  14. 一款网页游戏外挂开发-数据抓包
  15. 虚拟机的服务器管理器怎么打开,虚拟机启动任务管理器
  16. 读取数据快慢的设备_目前在以下各种设备中,读取数据快慢的顺序是内存、硬盘、光盘和软盘。...
  17. SpecCPU2017 测试cpu性能
  18. java递归20元买汽水,瓶盖递归 1块钱买一瓶水,三个瓶盖是换一瓶汽水,问20块钱能买 多少瓶汽水(不能借)...
  19. 下拉 html 实现原理,百度搜索下拉框实现技术原理分析
  20. 搜索功能(支持全拼,首字母,不区分大小写,关键字变色等)

热门文章

  1. rpx 和 rem 详解
  2. 大部分有高学历的人比低学历的人强
  3. 【JVM】运行时数据区概述(程序计数器、虚拟机栈、本地方法栈)
  4. 写给产品经理的第5封信:项目管理二三事
  5. 618投影仪怎么选?看看极米NEW Z6X、极米Z6X Pro与极米H3S
  6. 瘦手臂最快最有效的方法
  7. 我希望逢着一个丁香一样地结着愁怨的姑娘
  8. Word 实用技巧整理
  9. 开源在线客服系统源码(支持PC/H5/公众号/小程序)基于golang的网页在线客服系统...
  10. Hadoop集群性能测试