装饰模式(Decorator):动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
装饰模式的UML图:
Component是定义一个对象接口,可以给这些对象动态添加职责。ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。Decorator是装饰的抽象类,继承了Component,从外来类扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的,至于ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
下面就介绍一个具体的案例:
就是为一个人自由的搭配服饰,可以添加帽子,外套,裤子,鞋子,领带等装饰品。
首先,你先思考一下,如果让你设计这样的功能,你会怎样设计继承关系,然后在对照下列所用的装饰模式,比较二者的不同,和各自的优缺点。
搭配服饰类的UML图如下:
具体的类定义如下:
#include<iostream>
#include<string>
using namespace std;
//公共抽象类
class Persion
{
private:
string name;
public:
Persion()
{ }
Persion(string n) :name(n)
{ }
virtual void Show()
{
cout << "装扮者的姓名:" << name << endl;
}
};
//装饰抽象类
class Finery :public Persion//装饰的父类
{
protected:
Persion* component;
public:
//打扮
void Decorate(Persion* component)//相互装饰,这个函数起了重要的作用
{
this->component = component;
}
virtual void Show()
{
component->Show();//调用Persion类中的Show()
}
};
//具体的装饰类
class Tshirts :public Finery
{
public:
virtual void Show()
{
component->Show();//调用上一个装饰的Show()
cout << "T shirts"<<endl;
}
};
//具体的装饰类
class BigTrouser :public Finery
{
public:
virtual void Show()
{
component->Show();//调用上一个装饰的Show()
cout << "BigTrouser"<<endl;
}
};
//具体的装饰类
class Tie :public Finery
{
public:
virtual void Show()
{
component->Show();//调用上一个装饰的Show()
cout << "Tie" << endl;
}
};
//客户端
int main()
{
Persion* x=new Persion("小李");
Tshirts* ts=new Tshirts();
BigTrouser* bt = new BigTrouser();
Tie* tie = new Tie();
//装饰过程
ts->Decorate(x);
bt->Decorate(ts);
tie->Decorate(bt);
tie->Show();//递归式的调用各对象的Show()
return 0;
}
运行结果如下:
装饰模式是为已有的功能动态添加更多功能的一种方式。当系统需要新的功能时,如果向旧的类中添加新代码,就会增加类的复杂性,从而会产生对旧代码很难维护,因为每添加新的功能,就要修改旧类,在修改的过程中,难免不修改旧代码。然而,如果使用装饰模式,当增加新的装饰时,无需修改旧的代码,只需要增加新的类继承装饰抽象类即可。
装饰模式的优点:把类中的装饰功能从类中搬移出去,有效的把类的核心职责和装饰弄能区分开了,而且可以去除相关类中重复的装饰逻辑。