一 简介
装饰模式又叫包装模式,通过一种对客户端透明的方式来扩展对象功能,是继承关系的一种替代。
装饰模式就是把要附加的功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择的、按顺序的使用装饰功能包装对象。
二 UML图
- Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
- ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。
- Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。
- ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。
三 例子
装饰者模式实例
例如男人和女人可以被认为是被装饰者,做饭和洗衣服可以理解为装饰行为, 就是装饰者模式,在我看来最大的好处 就是行为与行为者可以分开,毕竟好扩展。 就是可以今天是男人做饭,女人洗衣服, 也可以是女人做饭 男人洗衣服。 接下来来实现这一行为
首先是基准类的头文件,男人女人都是人 所以以人作为基准类的声明如下,定义了两个纯虚函数,一个是人的属性,一个是人的行为。
//所有的基类 人
class People
{
public:
virtual void peopleAttribute() = 0; //人的属性
virtual void peopleBehavior() = 0; //人的行为
};
//被装饰者 :男人
class Man :public People
{
public:
void peopleAttribute();
void peopleBehavior();
};
void Man::peopleAttribute()
{
cout << "Man" ;
}
void Man::peopleBehavior()
{
cout << "Man 想要" ;
}
//被装饰者 :女人
class Woman :public People
{
public:
void peopleAttribute();
void peopleBehavior();
};
void Woman::peopleAttribute()
{
cout << "Woman" ;
}
void Woman::peopleBehavior()
{
cout << "Woman 想要" ;
}
//装饰者行为基类
class Decorate :public People
{
public:
Decorate(People * people) :m_people(people) {};
void peopleAttribute();
void peopleBehavior();
protected:
People * m_people;
};
void Decorate::peopleAttribute()
{
m_people->peopleAttribute();
}
void Decorate::peopleBehavior()
{
m_people->peopleBehavior();
}
//装饰者行为 做饭
class Cook :public Decorate
{
public:
Cook(People * people) :Decorate(people) {};
void peopleAttribute();
void peopleBehavior();
};
void Cook::peopleAttribute()
{
m_people->peopleAttribute();
cout << "饿了" << endl;
}
void Cook::peopleBehavior()
{
m_people->peopleBehavior();
cout << "做饭" << endl;
}
//装饰者行为 洗衣服
class Laundry :public Decorate
{
public:
Laundry(People * people) :Decorate(people) {};
void peopleAttribute();
void peopleBehavior();
};
void Laundry::peopleAttribute()
{
m_people->peopleAttribute();
cout << "衣服脏了" << endl;
}
void Laundry::peopleBehavior()
{
m_people->peopleBehavior();
cout << "洗衣服" << endl;
}
int main()
{
People * man = new Man();
People * woman = new Woman();
Decorate* cook = new Cook(man);
cook->peopleAttribute();
cook->peopleBehavior();
Decorate * laundry = new Laundry(woman);
laundry->peopleAttribute();
laundry->peopleBehavior();
delete man;
delete woman;
delete cook;
delete laundry;
getchar();
return 0;
}
结果图
四 装饰模式的优缺点
优点:
- 对于扩展一个对象的功能,装饰模式比继承更加灵活性,不会导致类的个数急剧增加。
- 可以通过一种动态的方式来扩展一个对象的功能,从而实现不同的行为。
- 可以对一个对象进行多次装饰。
- 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”。
缺点:
- 使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会占用更多的系统资源,影响程序的性能。
五 装饰者模式与适配器模式的区别
装饰者的目的是通过组合的方式给某个对象增加新的功能,与适配器不同,
适配器并不增加新的功能,而是将对象的某个功能转换成另一个接口需要的功能,从而达到适配的功能,此外还有代理模式,
代理则是将某个公共处理抽象出代理层,通过代理使用对象,代理更多的是将代理逻辑。