引入:
曾今以为继承能解决一切问题。在程序运行时发现,扩展的威力远大于编译时扩展的威力。
装饰者模式:
好处:
一旦知道装饰的技巧,你将能给你的(或别人的)对象一个新的责任,而不需要对底层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 无法实例化_beverage
virtual 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