意图:
动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
使用继承机制是添加功能的一种有效途径,从其他类继承过来的特性可以被多个子类的实例所使用。但这种方法不够灵活。用户不能选择对组件加特性的方式和时机。
一种较灵活的方式是将组件嵌入另一个对象中,由这个对象添加特性。我们称这个嵌入的对象叫装饰。
几个例子帮助理解:
QQ的换装系统,TextView对象显示滚动条和粗边框的例子,Java中的IO流的例子。
UML类图
Component是定义一个对象接口,可以给这些对象动态地添加职责。
ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。
Decorator是装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator存在的。
ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
例子:
1.大话设计模式上的例子:假设情景:某人装扮自己形象,穿衣服,裤子,鞋子,戴帽子等来把自己给包装起来
#include <iostream>
#include <string>
using namespace std;
class Person
{
private:
string name;
public:
Person(string name="") : name(name){}
virtual void Show()
{
cout<<"装扮的"<<name<<endl;
}
};
class Finery : public Person
{
protected:
Person *component;
public:
Finery() :Person(""), component(NULL) {}
void Decorate(Person *component)
{
this->component = component;
}
virtual void Show()
{
if (component!=NULL)
component->Show();
}
};
class TShirts : public Finery
{
public:
TShirts() : Finery(){}
virtual void Show()
{
cout<<"大T恤";
Finery::Show();
}
};
class BigTrouser : public Finery
{
public:
BigTrouser() : Finery(){}
virtual void Show()
{
cout<<"垮裤";
Finery::Show();
}
};
int main(int argc, char **argv)
{
Person *p = new Person("warringah");
cout<<"装扮:"<<endl;
TShirts *t = new TShirts();
BigTrouser *b = new BigTrouser();
t->Decorate(p);
b->Decorate(t);
b->Show();
system("pause");
return 0;
}
2.GOF书上的例子:TextView对象显示滚动条和粗边框的例子
#include <iostream>
#include <string>
using namespace std;
class Component
{
public:
Component(){}
virtual void Draw() = 0;
};
class ConcreteComponent : public Component
{
private:
string name;
public:
ConcreteComponent(string name) : Component(), name(name){}
virtual void Draw()
{
cout<<"draw a "<<name<<" component"<<endl;
}
};
class Decorator : public Component
{
private:
Component *component;
public:
Decorator(Component *component) : Component(), component(component){}
virtual ~Decorator()
{
delete component;
}
virtual void Draw()
{
if (component)
component->Draw();
}
};
class ScrollDecorator : public Decorator
{
private:
int depth;
void DrawScroll()
{
cout<<"add "<<depth<<" scrollBar"<<endl;
}
public:
ScrollDecorator(Component *component, int depth) : Decorator(component),
depth(depth){}
virtual void Draw()
{
Decorator::Draw();
DrawScroll();
}
};
class BorderDecorator : public Decorator
{
private:
int width;
void DrawBorder()
{
cout<<"add "<<width<<" borde"<<endl;
}
public:
BorderDecorator(Component *component, int width) : Decorator(component),
width(width){}
virtual void Draw()
{
Decorator::Draw();
DrawBorder();
}
};
int main(int argc, char **argv)
{
Component *p = new BorderDecorator(
new ScrollDecorator(
new ConcreteComponent("decoratored"), 12), 13);
p->Draw();
system("pause");
return 0;
}
总结一下:
装饰模式是为已有功能动态的添加更多功能的一种方式。在一边的设计中,当系统需要新功能时,是向旧的类中添加新的代码。这些新的代码通常装饰了原有类的核心职责或者主要行为。它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度。有时候,新加入的东西可能仅仅为了满足一些只在某种特定情况下才会执行的特殊行为的需要。
装饰模式提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地,按顺序的使用装饰功能包装对象了。
装饰模式将类中的装饰功能从类中搬移去除,可以简化原有的类。有效地把类的核心职责和装饰功能区分开,去除相关类中重复的装饰逻辑。
使用时要注意装饰的顺序。