设计模式03 - 装饰者模式
引入:
曾今以为继承能解决一切问题。在程序运行时发现,扩展的威力远大于编译时扩展的威力。
装饰者模式:
好处:
一旦知道装饰的技巧,你将能给你的(或别人的)对象一个新的责任,而不需要对底层class的代码做任何改变
p.s. 写代码的时候,尽量少对底层代码做修改。
描述:
装饰者模式动态地将额外责任附加到对象上。
对于扩展功能,装饰者提供子类化之外地弹性替代方案。
设计原则:
类应该对扩展开放,但对修改关闭。
我们的目标是允许类容易扩展以容纳新的行为,而不用修改已有代码。
达成这个目标,有什么好处?
这样的设计可以弹性地应对改变,有足够弹性接纳新的功能来应对改变的需求。
main.cpp
/*** @file main.cpp* @author JeffyGao (gaojune)better@qq.com)* * @version 0.1* @date 2022-04-30* @copyright Copyright (c) 2022* * @brief 本节开始介绍 设计模式03 - 装饰者模式* 文件描述:* Beverage.h:* class Beverage 基类 (抽象组件)* class CondimentDecorator : public Beverage 为调料实现抽象类 (抽象装饰者)* other_Drinks.h: 基于 Beverage (Beverage.h),派生的一些其它饮料* class Espresso : public Beverage 浓缩咖啡 (具体组件)* class TeaWithMilk : public Beverage 奶茶 (具体组件)* * other_Seasonings.h 基于 CondimentDecorator (Beverage.h),派生的一些其它调料* class Mocha : public CondimentDecorator 调料 - 摩卡 (具体装饰者)* class Cream : public CondimentDecorator 调料 - 奶油 (具体装饰者)* class Soy : public CondimentDecorator 调料 - 豆子 (具体装饰者)*/#include <iostream>
#include "Other_Drinks.h"
#include "Beverage.h"
#include "Other_Seasonings.h"// 开始下订单
class StabuzzCoffee{public:StabuzzCoffee( ){std::cout << "Begin buy my coffee ctor" << std::endl;}~StabuzzCoffee( ){std::cout << "StabuzzCoffee dtor" << std::endl;}
public:void Print( ){// std::cout << _beverage->GetDescription() << " $ " << _beverage->Cost() << std::endl;std::cout << _beverage->Cost() << "$" << std::endl;}public:Beverage* _beverage;
};// 点单系统是 一种奶茶/咖啡 + 若干小料
int main( ){std::cout << "No.1" << std::endl;// 来一杯浓缩咖啡,不加调料,打印出它的描述和价格StabuzzCoffee coffee1;coffee1._beverage = new Espresso();std::cout << coffee1._beverage->GetDescription() << std::endl;coffee1.Print();std::cout << "No.2" << std::endl;// 来一杯奶茶(0.89),加 摩卡(0.2)、奶油(0.31)// 在调用 coffee2.Pring() 的时候调用顺序:// -> Cream.Cost() -> Mocha.Cost() -> TraWithMilk.Cost() StabuzzCoffee coffee2;coffee2._beverage = new TeaWithMilk();coffee2._beverage = new Mocha( coffee2._beverage );coffee2._beverage = new Cream( coffee2._beverage );std::cout << coffee2._beverage->GetDescription() << std::endl;coffee2.Print();return 0;
}
Beverage.h
/*** @file Beverage.h* @author JeffyGao (gaojune)better@qq.com) * @version 0.1* @date 2022-04-30* @copyright Copyright (c) 2022* * @brief 这是一个抽象类 的基类* * 文件包含:* GetDescription() 商品描述* virtual double Cost() = 0 商品花费* * */#ifndef BEVERAGE_H
#define BEVERAGE_H#include <iostream>
#include <string.h>class Beverage{public:Beverage( ){std::cout << "Beverage ctor" << std::endl;}// 要定义 虚函数virtual ~Beverage( ){std::cout << "Beverage dtor" << std::endl;}public:// 公共接口// 商品描述virtual std::string GetDescription( ){return _description;}// 商品花费// 这里不能定义为 纯虚函数,不然 class CondimentDecorator 无法实例化_beveragevirtual double Cost( ) = 0;//virtual double Cost( ) {} // 如果要定义为虚函数的话要定义 {}// double Cost( ){// std::cout << " Beverage Cost()" << std::endl;// return (double)12345.1234;// }// 不能设置为 private,不然派生类无法更改改变量std::string _description = "Unknown Beverage ";};// 为调料实现抽象类
class CondimentDecorator : public Beverage{public:CondimentDecorator( ){std::cout << "CondimentDecorator ctor" << std::endl;}~CondimentDecorator( ){std::cout << "CondimentDecorator dtor" << std::endl;}public:// 书中这一行没看懂 => 在 Other_Seasonings.h 中要实例化// 我在 Beverage 中将 Cost( ) 定义了纯虚函数,因此不能直接实例化,只能实例化其指针// 要想能实例化其对象的话,另一种方法是定义好其虚构函数{}Beverage* _beverage;// 重写 GetDescription()virtual std::string GetDescription( ) {return _description;}};#endif
Other_Drinks.h
/*** @file Other_dring.h* @author effyGao (gaojune)better@qq.com)* @version 0.1* @date 2022-04-30* @copyright Copyright (c) 2022* * @brief 基于 基类 Beverage (Beverage.h),派生的一些其它饮料* * 文件包含:* class Espresso : public Beverage ,浓缩咖啡* Espresso() 更改 _description* Cost() 重写了 Cost()* class TeaWithMilk : public Beverage, 奶茶* TeaWithMilk() 更改 _description* Cost() 重写了 Cost()*/#ifndef OTHER_DRINKS_H
#define OTHER_DRINKS_H#include "Beverage.h"
#include <iostream>// 浓缩咖啡 (具体组件)
class Espresso : public Beverage{public:Espresso( ){//std::cout << "Espresso ctor" << std::endl;_description= "订单详情: 浓缩咖啡 "; // 并更改描述}~Espresso( ){std::cout << "Espresso dtor" << std::endl;}public:// 重写了 Cost()double Cost( ){std::cout << "共花费: ";return 1.99;}
};// 奶茶 (具体组件)
class TeaWithMilk : public Beverage{public:TeaWithMilk( ){//std::cout << "TeaWithMilk ctor" << std::endl;_description= "订单详情: 奶茶 "; // 并更改描述}~TeaWithMilk( ){std::cout << "TeaWithMilk dtor" << std::endl;}public:// 重写了 Cost()double Cost( ){std::cout << "共花费: ";return 0.89;}
};#endif
Other_Seaonings.h
/*** @file Other_Seasonings.h* @author effyGao (gaojune)better@qq.com)* @version 0.1* @date 2022-04-30* @copyright Copyright (c) 2022* * @brief 一些调料~ * 基于 基类 CondimentDecorator (Beverage.h),派生的一些其它调料* * 文件包含:* class Mocha : public CondimentDecorator 调料 - 摩卡 (具体装饰者)* class Cream : public CondimentDecorator 调料 - 奶油 (具体装饰者)* class Soy : public CondimentDecorator 调料 - 豆子 (具体装饰者)* * // 构造函数 传入 Beverage* 型, 在 main.cpp 中通过包裹对象来实现“加小料”,反馈相应的Cost()*/#ifndef OTHER_SEASONINGS_H
#define OTHER_SEASONINGS_H#include <iostream>
#include "Beverage.h"
#include <string>// 调料 - 摩卡 具体装饰着
class Mocha : public CondimentDecorator{public:Mocha( ){std::cout << "Mocha ctor" << std::endl;}Mocha( Beverage* beverage ){std::cout << "Mocha( Beverage beverage )" << std::endl;// 在这里实例变量为正在包裹的对象。// 这里,我们可以传递正在包装的饮料给装饰者的构造器。this->_beverage = beverage;}~Mocha( ){std::cout << "Mocha dtor" << std::endl;}public:// 重写方法// 饮料 Description + Mocha 描述std::string GetDescription( ){std::string name = _beverage->GetDescription() + " , Mocha";return name;}// 饮料 Cost + Mocha 价格double Cost( ){return _beverage->Cost() + 0.20;}
};// 调料 - 奶油 具体装饰着
class Cream : public CondimentDecorator{public:Cream( ){std::cout << "Cream ctor" << std::endl;}Cream( Beverage* beverage ){std::cout << "Cream( Beverage beverage )" << std::endl;// 在这里实例变量为正在包裹的对象。// 这里,我们可以传递正在包装的饮料给装饰者的构造器。this->_beverage = beverage;}~Cream( ){std::cout << "Cream dtor" << std::endl;}public:// 重写方法// 饮料 Description + Cream 描述std::string GetDescription( ){//std::cout << "调用了 奶油" << std::endl;std::string name = _beverage->GetDescription() + " , Cream";return name;}// 饮料 Cost + Cream 价格double Cost( ){return _beverage->Cost() + 0.31;}
};// 调料 - 豆子 具体装饰着
class Soy : public CondimentDecorator{public:Soy( ){std::cout << "Soy ctor" << std::endl;}Soy( Beverage* beverage ){std::cout << "Soy( Beverage beverage )" << std::endl;// 在这里实例变量为正在包裹的对象。// 这里,我们可以传递正在包装的饮料给装饰者的构造器。this->_beverage = beverage;}~Soy( ){std::cout << "Soy dtor" << std::endl;}public:// 重写方法// 饮料 Description + Soy 描述std::string GetDescription( ){std::string name = _beverage->GetDescription() + " , Soy";return name;}// 饮料 Cost + Soy 价格double Cost( ){return _beverage->Cost() + 0.39;}
};#endif
设计模式03 - 装饰者模式相关推荐
- Java设计模式(装饰者模式-组合模式-外观模式-享元模式)
Java设计模式Ⅳ 1.装饰者模式 1.1 装饰者模式概述 1.2 代码理解 2.组合模式 2.1 组合模式概述 2.2 代码理解 3.外观模式 3.1 外观模式概述 3.2 代码理解 4.享元模式 ...
- 前端也要学系列:设计模式之装饰者模式
什么是装饰者模式 今天我们来讲另外一个非常实用的设计模式:装饰者模式.这个名字听上去有些莫名其妙,不着急,我们先来记住它的一个别名:包装器模式. 我们记着这两个名字来开始今天的文章. 首先还是上< ...
- 设计模式 之 装饰者模式
2019独角兽企业重金招聘Python工程师标准>>> 设计模式 之 装饰者模式 装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对 ...
- 【设计模式】装饰者模式 ( 概念 | 适用场景 | 优缺点 | 与继承对比 | 定义流程 | 运行机制 | 案例分析 )
文章目录 I . 装饰者模式概念 II . 装饰者模式适用场景 III . 装饰者模式优缺点 IV . 装饰者模式与继承对比 V . 装饰者模式相关设计模式 VI . 装饰者模式四个相关类 VII . ...
- 设计模式学习----装饰器模式
这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大 ...
- 【设计模式】装饰器模式的使用
问题来源 我们在进行软件系统设计的时候,有一些业务(如下图,一些通用的非功能性需求)是多个模块都需要的,是跨越模块的.把它们放到什么地方呢? 最简单的办法就是把这些通用模块的接口写好,让程序员在实现业 ...
- C#设计模式(9)——装饰者模式(Decorator Pattern)
一.引言 在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类).A ...
- go设计模式之装饰器模式
go设计模式之装饰器模式 再写这篇文章时,我已经看了很多其他人发表的类似文章,大概看了这么多吧. 亓斌的设计模式-装饰者模式(Go语言描述) jeanphorn的Golang设计模式之装饰模式 七八月 ...
- python中的装饰器、装饰器模式_python 设计模式之装饰器模式 Decorator Pattern
#写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...
最新文章
- 深度学习目标检测(object detection)系列(一) R-CNN
- 解决TensorBoard训练集和测试集指标只能分开显示的问题(基于Keras)
- java spring 服务器关闭_通过springboot怎么停止服务器??
- android圆形进度条ProgressBar颜色设置
- 基本排序算法之4——归并排序mergesort
- 使用Eclipse连接SAP云平台上的HANA数据库实例
- opencv 最大连通域_opencv 查找连通区域 最大面积实例
- jzoj3853-帮助Bsny【dp】
- 详解异构计算FPGA基础知识
- php scope权限管理,关于微信公众号scope参数错误或没有scope权限的解决方案
- 【渗透测试实战】PHP语言有哪些后门?以及利用方法
- 初级程序员面试不靠谱指南(二)
- java从入门到入土_java从入门到入土---基础篇04---IO
- Hadoop配置文件( hadoop-env.sh、core-site.xml、hdfs-site.xm、mapred-site.xml、yarn-site.xml、 slaves)详解
- java进制转换方法
- 日更第17天:Linux常用命令之ps用法
- 电商基本功:被小瞧的促销设计,并没有想得那么简单
- 智能运维 | 我们不一样!告诉你百度云如何做智能流量异常检测
- Java实现HighCharts纯后台图表生成
- 性能测试方案与性能测试报告目录导航
热门文章
- 基于C#实现的在线聊天室的桌面系统软件
- 专升本——非谓语动词
- 【数学建模】“一口价”的战略(博弈模型)
- 计算机体系架构(1)计算机组成原理
- 提问的艺术 | 如何聪明地提问
- 数据库的视图,视图的更新,视图的可操作性
- java web 开发是做什么用的?
- python单词词典_Python自然语言处理学习笔记(42):5.3 使用Python字典将单词映射到属性...
- 基于ESP32的SPI读取MPU9250数据
- windows 如何查看、修改MAC地址?