C++之装饰(decorator)模式
原创
©著作权归作者所有:来自51CTO博客作者敢敢的wings的原创作品,请联系作者获取转载授权,否则将追究法律责任
0. 简介
很多时候我们在接手代码的时候会发现很多时候我们需要在原本基础的类中加入一些功能,或者要调用多个类来组合成一个新类来工作。这时候我们需要使用装饰或者适配器模式来对整个结构去聚合或者多重继承出自己想要的类型。装饰模式是一种结构型设计模式,其可以动态的为一个类增加职责(相对于继承)。


1装饰模式

- 部件 (Component) 声明封装器和被封装对象的公用接口。
- 具体部件 (Concrete Component) 类是被封装对象所属的类。 它定义了基础行为, 但装饰类可以改变这些行为。
- 基础装饰 (Base Decorator) 类拥有一个指向被封装对象的引用成员变量。 该变量的类型应当被声明为通用部件接口, 这样它就可以引用具体的部件和装饰。 装饰基类会将所有操作委派给被封装的对象。
- 具体装饰类 (Concrete Decorators) 定义了可动态添加到部件的额外行为。 具体装饰类会重写装饰基类的方法, 并在调用父类方法之前或之后进行额外的行为。
- 客户端 (Client) 可以使用多层装饰来封装部件, 只要它能使用通用接口与所有对象互动即可。
2. 装饰模式示例
装饰模式和生成器模式类似,都没有一个合适的template模板类来便捷的导入,这里我们可以看一下这篇文章中的代码。来感受一下装饰模式的魅力。
#include "iostream"
using namespace std;
// 部件
class Component_CS {
public:
virtual ~Component_CS() {}
//const表示this是一个指向常量的指针,=0表示这个成员函数是纯虚函数
virtual void fire() const = 0;
};
// 具体部件
class ConcreteComponent_CS
{
public :
ConcreteComponent_CS(){}
virtual ~ConcreteComponent_CS(){}
virtual void fire() const
{
cout<<"反恐精英:"<<endl;
}
// void fire() const override
// {
// cout<<"反恐精英:"<<endl;
// }
// 如果没有实例化,就需要加上virtual or override
// void fire() const
// {
// cout<<"反恐精英:"<<endl;
// }
};
//基础装饰
class Weapon : public Component_CS
{
protected:
Component_CS * person;
public:
Weapon(){}
virtual ~Weapon(){}
//装饰函数
void Decorate(Component_CS * p)
{
person = p;
}
virtual void fire()
{
person->fire();
}
};
//具体装饰
class Ak47 : public Weapon
{
public :
virtual void fire()
{
Weapon::fire();
cout<<"AK47射击"<<endl;
}
};
//具体装饰
class Pistol : public Weapon
{
public :
virtual void fire()
{
Weapon::fire();
cout<<"手枪射击"<<endl;
}
};
//具体装饰
class Dagger : public Weapon
{
public :
virtual void fire()
{
Weapon::fire();
cout<<"捅你"<<endl;
}
};
main()
{
Component_CS * person = new ConcreteComponent_CS();
Weapon * ak = new Ak47();
Weapon * pistol = new Pistol();
Weapon * dagger = new Dagger();
ak->Decorate(person);
pistol->Decorate(ak);
dagger->Decorate(pistol);
dagger->fire();
}

我们可以看到在main函数中,我们可以通过装饰类的嵌套来将一个函数开发出更多的功能且不会影响前面类的输出。这对于我们去无需修改代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式。同时如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用装饰模式。
3. 装饰器的优缺点
一般给对象添加新的功能可能会通过继承的方式来解决,但是呢,继承会带来的问题就是,子类越来越多且会越来越臃肿。 我们知道在七大设计原则中有一条就是【组合/聚合复用原则】。在拥有很多组合方式的时候,我们应该优先使用组合而不是继承,装饰器模式在这个原则表现的就很强烈。
下一章我们讲的适配器模式可以对已有对象的接口进行修改, 装饰模式则能在不改变对象接口的前提下强化对象功能。 此外, 装饰还支持递归组合, 适配器则无法实现。

4. 七大设计原则