装饰模式(Decorator)
动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。(将所需功能安照正确的顺序串联起来进行控制。衣服在内部穿好在show)
经典的错误代码:Person类 里面不同的方法,穿不同的衣服。新增种类,则新增函数,客户端代码都需要重新改,违背了开放封闭原则。
UML类图
Component(组件)是定义一个对象接口,可以给这些对象动态的添加职责。ConcreteComponent(具体组件)是定义一个具体的对象,也可以给这个对象添加一些职责。
Decorator,装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,无需知道Decorator的存在的。至于ConcreteComponent就是具体的装饰对象,起到给Component添加职责的功能。实际中可将ConcreteComponent 和Component合并为一个类
C++代码实现
//组件类
class Component {
public:
virtual void Operator() { cout << "Component::Operator():组件类的操作 " << endl; }
};
//具体组件类
//具体的装饰对象,起到给Component添加职责的功能
class ConcreteComponent: public Component {
public:
void Operator()
{
cout << "ConcreteComponent::Operator():具体对象的操作 " << endl;
}
};
// 装饰抽象类,继承了Component,从外类来扩展Component类的功能,
//但对于Component来说,无需知道Decorator的存在的。
class Decorator :public Component {
private:
Component *_component;
public:
//设置Component
void setComponent(Component *component)
{
this->_component = component;
}
//重写 Operator() 实际执行的是ComponentOperator()
void Operator()
{
//if (_component!=NULL)
{
// cout << "Decorator::Operator():装饰抽象类的操作 " << endl;
_component->Operator();
}
}
};
class ConcreteDecoratorA :public Decorator {
private:
int _a; //本类独有功能,以区别ConcreteDecoratorB
public:
void Operator()
{
Decorator::Operator();//先运行Component::Operator(),在执行本类的功能,相当于对Component进行装饰
_a = 10;
cout << "ConcreteDecoratorA::Operator():ConcreteDecoratorA的操作 :"<<_a << endl;
}
};
class ConcreteDecoratorB :public Decorator {
public:
//本类独有功能,以区别ConcreteDecoratorA
void funB()
{ cout << "ConcreteDecoratorB::funB();"<< endl; }
void Operator()
{
Decorator::Operator();//先运行Component::Operator(),在执行本类的功能,相当于对Component进行装饰
funB();
cout << "ConcreteDecoratorB::Operator():ConcreteDecoratorB的操作 :"<< endl;
}
};
int main()
{
std::cout << "Hello World!\n";
Component *cc= new Component;
ConcreteDecoratorA *a1 = new ConcreteDecoratorA;
ConcreteDecoratorB *b1 = new ConcreteDecoratorB;
a1->setComponent(cc); //装饰的方法首先ConcreteComponent实例化对象cc,然后用ConcreteDecoratorA实例化的对象a1包装cc
b1->setComponent(a1); //用ConcreteDecoratorB实例化的对象b1包装a1,调用b1的Operator();
b1->Operator();
}
输出:
Component::Operator():组件类的操作
ConcreteDecoratorA::Operator():ConcreteDecoratorA的操作 :10
ConcreteDecoratorB::funB();
ConcreteDecoratorB::Operator():ConcreteDecoratorB的操作 :
// //首先ConcreteDecoratorB 的Operator(),先执行基类Decorator::Operator() ,在基类Decorator::Operator()中
//会根据设置的Component对象是谁,决定调用谁的Operator(),由于b1->setComponent(a1);设置Component对象为ConcreteDecoratorA
//故到ConcreteDecoratorA 的Operator(),由于A设置的Component对象是Component,故先Component::Operator(),然后A的。然后B的。
//栈中 ConcreteDecoratorB::Operator()-》ConcreteDecoratorA::Operator()->Component::Operator()。 故打印顺序如上。
3.何时用。装饰模式是对已有功能动态的添加更多功能的一种方式。经典的错误做法,向旧类中添加新代码,新加的代码装饰了原有类的核心职责或是主要行为,增加了主类的复杂程序。
而装饰模式提供了一个非常好的解决方案,把每个要装饰的功能单独放在一个类中,并让这个类包装它所要修饰的对象,因此当需要执行特殊行为时,客户端代码就可以在运行时根据需要有选择地,按顺序地使用装饰功能包装对象了。
4.优点:把类中装饰功能从类中搬移去除,这样可以简化原有的类。有效地把类的核心职责和装饰功能区分开,而且可以去除相关类中重复的装饰逻辑。
注意:装饰模式的装饰顺序很重要。比如加密数据和过滤词汇都可以是数据持久化前的装饰功能,但若先加密了数据再用过滤功能就会出问题。最理想的情况保证装饰类之间彼此独立,这样他们就饿可以以任意的顺序进行组合。(先穿西装,在套T恤不是个好的方法)