装饰器模式允许向一个现有对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装(装饰器模式是用来给对象增加某些特性或者对被装饰对象进行某些修改)。
一般情况通过类的继承来扩展功能,装饰器模式可以动态的给类增加功能
// 主要解决:我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
// 意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
// 需要扩展一个类的功能,或给一个类增加附加责任。
// 需要动态的给一个对象增加功能,这些功能可以再动态地撤销。
// 需要增加一些基本功能的排列组合而产生的非常大量的功能。
// 何时使用:在不想增加很多子类的情况下扩展类。
// 如何解决:将具体功能职责划分,同时继承装饰器模式。
//注意:装饰者模式的根本是装饰而不是改变接口,原先调用的什么接口,最后还是会调用到这个接口,也就是装饰角色的接口与抽象构件角色的接口是完全一致的,也叫做完全透明装饰者模式,反之如果接口发生了改变,那就是一种适配器了。
装饰器模式的优点:
1、可以轻松对已存在的对象进行修改和包装,在被装饰者的前面或者后面添加自己的行为,而无需修改原对象。
2、可以动态、不限量地进行装饰,可以更灵活地扩展功能。
相对地,装饰器模式有很明显的缺点:
1、会加入大量的小类,即使只添加一个功能,也要额外创建一个类,使得程序更复杂。
2、增加代码复杂度,使用装饰器模式不但需要实例化组件,还要把组件包装到装饰者中。
//核心功能(已有功能)-抽象英雄
class AbstractHero {
public:
virtual void showState() = 0;
public:
int mAt;//攻击
int mDf;//防御
};
//具体英雄
class Hero :public AbstractHero
{
public:
Hero() {
mAt= 0;//攻击
mDf= 0;//防御
}
public:
virtual void showState() {
cout << "白班英雄 攻击 = " << mAt << endl;
cout << "白班英雄 防御 = " << mDf << endl;
}
};
//抽象装饰器类-具体穿装备的英雄
class AbstractDecoratorHero :public AbstractHero
{
public:
AbstractDecoratorHero(AbstractHero* hero) {
this->pHero = hero;
}
virtual void showState() {}
public:
AbstractHero* pHero;
};
//具体装饰器类-具体穿衣服的英雄
class ClothingDecoratorHero :public AbstractDecoratorHero
{
public:
ClothingDecoratorHero(AbstractHero* hero) :AbstractDecoratorHero(hero) {}
//具体穿装备
void addColthing() {
cout << "英雄装备衣服 :" << endl;
this->mAt = this->pHero->mAt;
this->mDf = this->pHero->mDf + 30;
delete this->pHero;
}
virtual void showState() {
addColthing();
cout << "攻击 = " << mAt << endl;
cout << "防御 = " << mDf << endl;
}
};
//调用者-invoke
void test() {
AbstractHero* hero = new Hero;
hero->showState();
cout << "给白班英雄装备衣物" << endl;
hero = new ClothingDecoratorHero(hero);
hero->showState();
}
饰模式重点在装饰,对核心功能的装饰作用;将继承中对子类的扩展转化为功能类的组合,从而将需要对子类的扩展转嫁给用户去进行调用组合,用户如何组合由用户去决定。装饰是在一个核心功能上添加一些附属功能,从而让核心功能发挥更大的作用,但是最终它的核心功能是不能丢失的。这就好比,我们的装饰就是给核心功能添加了一层外衣,让它看起来更漂亮和完美。