装饰模式
我们需要把所需的功能按正确的顺序串联起来进行控制,比如 先穿衣服—>裤子—>鞋子—>领带, 当然相反也可以
装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
代码举例
decorator.h
#ifndef DECORATOR_H
#define DECORATOR_H
#include <string>
#include <iostream>
using namespace std;
//装饰模式
class Component
{
public:
virtual void Operation() = 0;
};
class ConcreteComponent:public Component
{
public:
void Operation();
};
class Decorator:public Component
{
public:
Component *component;
void setComponent(Component *component);
virtual void Operation() = 0;
};
class ConcreteDecoratorA:public Decorator
{
public:
void Operation();
private:
string addedState;
};
class ConcreteDecoratorB:public Decorator
{
public:
void Operation();
private:
void addedBehavior();
};
#endif // DECORATOR_H
decorator.cpp
#include "decorator.h"
void Decorator::setComponent(Component *component)
{
this->component = component;
}
void Decorator::Operation()
{
if(this->component != nullptr)
{
this->component->Operation();
}
}
void ConcreteComponent::Operation()
{
cout<<"ConcreteComponent::Operation()"<<endl;
}
void ConcreteDecoratorA::Operation()
{
this->component->Operation();//首先运行原Component的Operation()
this->addedState = "new state";//再执行本类的功能,相当于对原Component进行了装饰饰
cout<<"ConcreteDecoratorA::Operation()"<<endl;
}
void ConcreteDecoratorB::Operation()
{
this->component->Operation();//首先运行原Component的Operation()
this->addedBehavior();//再执行本类的功能,相当于对原Component进行了装饰饰
cout<<"ConcreteDecoratorB::Operation()"<<endl;
}
void ConcreteDecoratorB::addedBehavior()
{
cout<<"ConcreteDecoratorB::addedBehavior()"<<endl;
}
main.cpp
int main()
{
ConcreteComponent *c = new ConcreteComponent();
ConcreteDecoratorA *d1 = new ConcreteDecoratorA();
ConcreteDecoratorB *d2 = new ConcreteDecoratorB();
d1->setComponent(c);
d2->setComponent(d1);
d2->Operation();
return 0;
}
- 装饰的方法是:首先用ConcreteComponent实例化对象c,然后用ConcreteDecoratorA 的实例化对象d1来包装c,再用ConcreteDecoratorB 的对象d2包装d1,最终执行d2的Operation()
- 装饰模式是利用SetComponent来对对象进行包装的,这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中,顺序随意,灵活的
- 学习模式要善于变通,如果只有一个ConCreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类,同样道理,如果只有一个ConcreteDecorator类,那么就没必要建立一个单独的Decorator类,而可以把Decorator和Concrete Decorator的责任合并成一个类
再举例
person.h
#ifndef PERSON_H
#define PERSON_H
#include <iostream>
#include <string>
using namespace std;
//人类(ConcreteComponent)
class Person
{
private:
string name;
public:
Person(){}
Person(string name)
{
this->name = name;
}
virtual void show()
{
cout<<"is "<<name<<endl;
}
};
//服装类(Decorator)
class Finery:public Person
{
protected:
Person *component;
//打扮
public:
void Decorate(Person *component)
{
if(component != nullptr)
{
this->component = component;
}
}
void show()
{
if(component != nullptr)
{
component->show();
}
}
};
//具体服装类(ConcreteDecorator)
class TShirts:public Finery
{
public:
void show()
{
cout<<"TShirts ";
this->component->show();
}
};
class BigTrouser:public Finery
{
public:
void show()
{
cout<<"BigTrouser ";
this->component->show();
}
};
class Sneakers:public Finery
{
public:
void show()
{
cout<<"Sneakers ";
this->component->show();
}
};
#endif // PERSON_H
main.cpp
int main()
{
Person *Nemo = new Person("Nemo");
Sneakers *s = new Sneakers();
BigTrouser *bt = new BigTrouser();
TShirts *t = new TShirts();
s->Decorate(Nemo);
bt->Decorate(s);
t->Decorate(bt);
t->show();
return 0;
}
结果显示:TShirts BigTrouser Sneakers is Nemo
装饰模式是为了已有功能动态地添加更多功能的一种方式。但是到底什么时候用它呢?
当系统需要新功能的时候,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为,比如用西服和鞋子装饰小明,但这种做法的问题在于,它们在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,就像最初设计了一个类,不考虑扩展的话,当有新需求的时候,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户端代码就可以在运行的时候根据需要有选择地,按顺序地使用装饰功能包装对象了
总结:装饰模式的优点就是把类中的装饰功能从类中搬移去除,这样可以简化原有的类,而且更有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中的重复的装饰逻辑