装饰模式:
装饰模式又叫包装模式,通过—种对客户端透明的方式来扩展对象功能,是继承关系的一种替代装饰模式就是把要附加的功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择的、按顺序的使用装饰功能包装对象。
一般情况下用继承实现类的功能拓展
装饰模式可以动态给一个类增加功能
在装饰模式中的各个角色有:
抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
具体装饰(Concrete Decorator)角色:负责给构件对象”贴上”附加的责任。
适用场景与优缺点:
在以下情况下应当使用装饰模式:
1.需要扩展一个类的功能,或给一个类增加附加责任。
2.需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。
优点:
1.Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
2.通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
缺点:
1.这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
2.装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
3.装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
类图:
代码示例:
抽象英雄类,具体英雄类,抽象装饰物,具体装饰物
一个英雄装上蓝水晶后,他的MP变多了,但是他还是一个英雄,这个对象的本质没变,但是他的功能变了
#include <iostream>
using namespace std;
//抽象英雄类
class AbstractHero {
public:
virtual void ShowStatic() = 0;
public:
int m_HP;
int m_MP;
};
//具体英雄类
class HeroA : public AbstractHero {
public:
HeroA() {
m_HP = 0;
m_MP = 0;
}
virtual void ShowStatic() {
cout << "血量:" << m_HP << endl;
cout << "蓝量:" << m_MP << endl;
}
};
//穿上装饰物后
class AbstractEquipment:public AbstractHero
{
public:
AbstractEquipment(AbstractHero* hero) {
this->phero = hero;
}
virtual void ShowStatic() = 0;
public:
AbstractHero* phero;
};
//蓝水晶
class A_Equipment : public AbstractEquipment
{
public:
A_Equipment(AbstractHero* hero):AbstractEquipment(hero){}
//增加额外功能
void Add_A() {
this->m_HP = this->phero->m_HP;
//英雄装上蓝水晶,蓝量加30
this->m_MP = this->phero->m_MP + 30;
}
virtual void ShowStatic() {
Add_A();
cout << "血量:" << m_HP << endl;
cout << "蓝量:" << m_MP << endl;
}
};
void test() {
AbstractHero* hero = new HeroA;
hero->ShowStatic();
cout << "-----------------------" << endl;
cout << "装上蓝水晶后:" << endl;
hero = new A_Equipment(hero);
hero->ShowStatic();
}
int main() {
test();
return 0;
}