1. 模式动机
一般有两种方式可以实现给一个类或对象增加行为:
- 继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
- 关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator). 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。
2. 模式定义
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。
类图:
3. 例子
需求: 给不同的人添加不同的衣服
/*
* @Author: sanjayzhong
* @Github: https://github.com/sanjayzzzhong
* @Date: 2019-12-05 10:36:24
*/
//装饰模式
//需求: 可以给人增加各种服饰的功能, 服饰不定
//用装饰模式, 写一个抽象人类, 用一个装饰器继承这个类, 同时里面聚合抽象人类
#include <iostream>
#include <string>
using namespace std;
//1.抽象人基类
class AbstractPerson{
public:
AbstractPerson(string name):m_name(name){}
virtual void show() = 0;
string m_name;
};
//2.人类
class Person : public AbstractPerson{
public:
Person(string name) : AbstractPerson(name){
}
void show(){
cout << m_name << " is a Person" << endl;
}
};
//3.抽象修饰基类
//装饰器的重点: 需要继承需要装饰的类, 同时类里面还需要聚合需要装饰的类
//继承是为了可以访问需要装饰类的内容, 聚合是为了拥有需要装饰类的实例
class AbstractDecorator : protected AbstractPerson{
public:
AbstractPerson* m_ab_person;
AbstractDecorator(AbstractPerson* ab_person): AbstractPerson(ab_person->m_name){
m_ab_person = ab_person;
}
virtual void show() = 0;
};
//4. 具体修饰类
class DecoratorA : public AbstractDecorator{
public:
DecoratorA(AbstractPerson* ab_person) : AbstractDecorator(ab_person){
}
virtual void show() override{
//增加的服饰
cout << "穿上衣" << endl;
this->m_ab_person->show(); //原来的服饰
}
};
int main(int argc, char const *argv[])
{
AbstractPerson* p1 = new Person("sanjay");
p1->show();
//装饰模式, 给p1增加衣服
AbstractDecorator* cloth = new DecoratorA(p1);
cloth->show();
return 0;
}