作用:
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。简单的来说,就是已经有一个类了,这个类中有一些功能,现在想给这个类多增加几个功能,使这个类的功能更强大。
举个例子:
麦当劳的炸鸡腿很好吃,但有些客户总是喜欢在炸鸡腿上挤上一些芝士,那才是人间美味,这样,在制作炸鸡腿之后,才需要挤芝士,因此挤芝士这个动作可以看作是后续对整个炸鸡腿的装饰。
装饰模式和适配器模式的关系:
相同点:
两者都是包装模式,都是通过封装其他的对象达到设计的目的。
不同点:
理想的装饰模式对对象功能的增强之外,保持装饰角色与抽象类的接口一致,但是适配器模式则不同,适配器模式不要求增强被装饰对象的功能、改变接口达到和被装饰者同样的功能。
装饰模式有半透明和透明之分,透明的装饰模式就是理想的装饰模式,保持了接口的一致性,半透明的装饰模式在某种意义上来说,已经相当于一个适配器的角色。
透明性:
就是说,客户端需要申明一个Component的变量,而不是其派生类ConcreteComponent的变量。
Chicken* com = new ConcreteComponent();
Decorator* dec= new ConcreteDecorator(com);
而不能申明为
ConcreteDecorator* dec= new ConcreteDecorator(com);
也就是说, 鸡腿就是鸡腿,并不是说加了芝士的鸡腿就不是鸡腿而是芝士了。
半透明:
就是说有了ConcreteDecorator,那么我们就可以调用只有ConcreteDecorator才有的方法,半透明的装饰模式是介于装饰模式和适配器模式之间的。
优缺点:
- 装饰类的排列组合,可以增加更多的行为。
- 相对于继承而言,可以动态的增加或者去除装饰的功能,更灵活。(继承只能静态的改变)
- 装饰模式,装饰类的对象比继承的更多,增加复杂度,特别是查问题的时候。
例子:
#include<iostream>
using namespace std;
//抽象基类,定义一个对象接口,可以为这个接口动态的添加职责.
class Chicken
{
public:
Chicken(){}
virtual ~Chicken(){}
virtual void MakeChicken() = 0;
};
class Decorator : public Chicken
{
public:
Decorator(Chicken* com)
{
this->_com = com;
}
virtual ~Decorator()
{
delete _com;
}
void MakeChicken(){}
protected:
Chicken* _com;
};
class ChickenA: public Chicken
{
public:
ChickenA(){}
~ChickenA(){}
void MakeChicken()
{
cout << "make fried chicken leg..." << endl;
}
};
//派生自Decorator,这里代表为ChickenA动态添加职责的类
class Cheese: public Decorator
{
public:
Cheese(Chicken* com) : Decorator(com){}
virtual ~Cheese(){}
virtual void MakeChicken()
{
Decorator::_com->MakeChicken();
this->PutCheese();
}
void PutCheese()
{
cout << "top the fried chicken with cheese..." << endl;
}
};
int main()
{
//初始化一个 Component 对象
Chicken* com = new ChickenA();
Decorator* dec = new Cheese(com);
dec->MakeChicken();
//动态的为ChickenA类添加一些功能
// Cheese* conDec = new Cheese(com);
// conDec->PutCheese();
// delete conDec;
// conDec = NULL;
delete dec;
dec = NULL;
return 0;
}
UML类图: