设计模式C++装饰
参考视频:【设计模式(完整版)】2.4装饰_哔哩哔哩_bilibili
分类:(对象)结构型
问题:饮料店订单系统,饮料有多种,并且可以选择加牛奶,冰激凌,巧克力等配料.
解决方案:动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更加灵活.找出基本组件和可选层次.
1.组件(Component)声明封装器和被封装对象的共用接口.
2.具体组件(Concrete Component)类是被封装对象所属的类.它定义了基础行为,但装饰类可以改变这些行为.
3.基础装饰(Base Decorator)类拥有指向被封装对象的引用成员变量.装饰基类会将所有操作委派给被封装的对象.
4.具体装饰类(Concrete Decorators)定义了可动态添加到组件的额外行为.具体装饰类会重写装饰基类的方法,并在调用父类方法之前或之后进行额外的行为.
5.客户端(Client)可以使用多层装饰来封装部件,只要它能使用通用接口与所有的对象互动即可.
再看一个例子,使用装饰模式能够对敏感数据进行压缩和加密:
优点:
无需创建子类即可拓展对象的行为.
可以在运行时添加或删除对象的功能.
可以用多个装饰封装对象来组合几种行为.
单一职责原则.将实现了许多不同行为的大类拆分为多个较小的类.
缺点:
在封装器栈中删除特定封装器比较困难.
实现行为不受装饰栈顺序影响的装饰比较困难.
各层的初始化配置代码看上去可能会很糟糕.
代码:
#include <iostream>
#include <string>
//接口:具体被包裹的类,以及装饰类
class Beverage
{
public:
virtual ~Beverage() {}
virtual std::string Operation() const = 0;
};
//具体的被装饰者
class Americano :public Beverage
{
public:
~Americano() {}
std::string Operation() const override
{
return "美式咖啡";
}
};
//装饰
//基础部分(可能包括额外部分)
class Ingredient :public Beverage
{
protected:
Beverage* m_beverage;
public:
~Ingredient() {};
Ingredient(Beverage* beverage) :m_beverage(beverage) {}
std::string Operation() const override
{
//核心代码,不是被用来被基类覆盖的
return m_beverage->Operation();
}
};
//额外部分(需要委托基类完成基础部分)不能直接继承Beverage
class Whip :public Ingredient
{
public:
~Whip() {}
Whip(Beverage* beverage) :Ingredient(beverage)
{
}
std::string Operation() const override
{
//在基类的Operation之前,之后都可以增加额外的操作
return "奶昔("+Ingredient::Operation()+")";
}
};
class Mocha :public Ingredient
{
public:
~Mocha() {}
Mocha(Beverage* beverage) :Ingredient(beverage)
{
}
std::string Operation() const override
{
//在基类的Operation之前,之后都可以增加额外的操作
return "摩卡(" + Ingredient::Operation() + ")";
}
};
void ClientCode(Beverage* beverage)
{
std::cout << "执行结果:" << beverage->Operation();
}
int main()
{
std::cout << "来一杯普通美式咖啡" << std::endl;
Beverage* americano = new Americano();
ClientCode(americano);
std::cout << std::endl;
std::cout << "来一杯双份摩卡+奶昔的美式咖啡" << std::endl;
Beverage* whip1 = new Whip(americano);
Beverage* mocha1 = new Mocha(whip1);
Beverage* mocha2 = new Mocha(mocha1);
ClientCode(mocha2);
delete americano;
delete whip1;
delete mocha1;
delete mocha2;
}