参考:
[装饰器模式 (refactoringguru.cn)](https://refactoringguru.cn/design-patterns/bridge)
design-patterns-cpp/decorator at master · JakubVojvoda/design-patterns-cpp · GitHub
一、什么是装饰器模式?
定义:在不改变已有对象的属性和方法的前提下,对已有对象的属性和功能进行拓展。
扩展一个对象,最常用的方法是在它所属类中添加成员或者方法,或者使用继承,创建新类。但是这些方法都是静态的,当你需要扩展的功能是可以选择的时候,你需要使用动态的方式给用户提供选择。
比如,你已经有一扇窗了,但你想选择是否需要增加纱窗,在已有的这扇窗上扩展,而不是其它的窗户。最典型的例子是煎饼果子。每个客户都有一个原始的煎饼果子,可以根据喜好来添加辅料。可以加火腿,加完火腿后还可以加鸡蛋,继续加培根等等。这就像俄罗斯套娃,在一个原始对象上不断增加功能,而不改变它。
二、实现
装饰器(Decorator)模式包含以下主要角色:
- 抽象构件(Component):定义一个接口,确定原始组件的基本功能。
- 具体构件(ConcreteComponent):实现接口,它就是被装饰者。
- 抽象装饰(Decorator):继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
- 具体装饰(ConcreteDecorator):实现抽象装饰的相关方法,并给具体构件对象添加功能。
1、Decorator.cpp
/*
* C++ Design Patterns: Decorator
* Author: Jakub Vojvoda [github.com/JakubVojvoda]
* 2016
*
* Source code is licensed under MIT License
* (for more details see LICENSE)
*
*/
#include <iostream>
/*
* Component
* 实现接口,它就是被装饰者。
*/
class Component
{
public:
virtual ~Component() {}
virtual void operation() = 0;
// ...
};
/*
* Concrete Component
* 定义一个接口,确定原始组件的基本功能。
*/
class ConcreteComponent : public Component
{
public:
~ConcreteComponent() {}
void operation()
{
std::cout << "Concrete Component operation" << std::endl;
}
// ...
};
/*
* Decorator
* 继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
*/
class Decorator : public Component
{
public:
~Decorator() {}
Decorator( Component *c ) : component( c ) {}
virtual void operation()
{
component->operation();
}
// ...
private:
Component *component;
};
/*
* Concrete Decorators
* 具体的装饰者,给具体构件对象添加功能。
*/
class ConcreteDecoratorA : public Decorator
{
public:
ConcreteDecoratorA( Component *c ) : Decorator( c ) {}
void operation()
{
Decorator::operation();
std::cout << "Decorator A" << std::endl;
}
// ...
};
class ConcreteDecoratorB : public Decorator
{
public:
ConcreteDecoratorB( Component *c ) : Decorator( c ) {}
void operation()
{
Decorator::operation();
std::cout << "Decorator B" << std::endl;
}
// ...
};
int main()
{
ConcreteComponent *cc = new ConcreteComponent();
ConcreteDecoratorB *db = new ConcreteDecoratorB( cc );
ConcreteDecoratorA *da = new ConcreteDecoratorA( db );
Component *component = da;
component->operation();
delete da;
delete db;
delete cc;
return 0;
}
装饰器模式所包含的 4 个角色不是任何时候都要存在的,在有些应用环境下模式是可以简化的,如以下两种情况。
(1) 如果只有一个具体构件而没有抽象构件时,可以让抽象装饰继承具体构件,其结构图如图 4 所示。
(2) 如果只有一个具体装饰时,可以将抽象装饰和具体装饰合并,其结构图如图 5 所示。
2、煎饼果子
#include <iostream>
#include <string>
class Component
{
public:
virtual ~Component() {}
virtual std::string GetName() = 0;
virtual double GetPrice() = 0;
};
// 煎饼
class PanCake : public Component
{
public:
~PanCake() {}
std::string GetName() override {
return "PanCake";
}
double GetPrice() override {
return 5.0;
}
};
class Decorator : public Component
{
public:
~Decorator() {}
Decorator( Component *c ) : component( c ) {}
std::string GetName() override {
return component->GetName();
}
double GetPrice() override {
return component->GetPrice();
}
private:
Component *component;
};
// 煎饼+鸡蛋
class PanCakeWithEgg : public Decorator
{
public:
PanCakeWithEgg( Component *c ) : Decorator( c ) {}
std::string GetName() override {
return Decorator::GetName() + "+Egg";
}
double GetPrice() override {
return Decorator::GetPrice() + 1.5;
}
// ...
};
// 煎饼+火腿
class PanCakeWithHam : public Decorator
{
public:
PanCakeWithHam( Component *c ) : Decorator( c ) {}
std::string GetName() override {
return Decorator::GetName() + "+Ham";
}
double GetPrice() override {
return Decorator::GetPrice() + 2.0;
}
};
int main()
{
PanCake *aa = new PanCake();
PanCakeWithEgg *bb = new PanCakeWithEgg( aa );
PanCakeWithHam *cc = new PanCakeWithHam( bb );
std::cout << aa->GetName() << " Price: " << aa->GetPrice() << std::endl;
std::cout << bb->GetName() << " Price: " << bb->GetPrice() << std::endl;
std::cout << cc->GetName() << " Price: " << cc->GetPrice() << std::endl;
delete cc;
delete bb;
delete aa;
return 0;
}
输出:
PanCake Price: 5
PanCake+Egg Price: 6.5
PanCake+Egg+Ham Price: 8.5
三、优缺点,适用场景
优点
- 遵守开闭原则,在不改变原有对象的情况下,动态的给一个对象扩展功能。
- 通过选择的排列组合,可以实现不同效果。
缺点
- 装饰器模式会增加许多子类,过度使用会增加程序得复杂性。