概念
装饰( Decorator )模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。
装饰模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择地、按顺序地使用装饰功能包装对象。
可以在运行的时候动态的为component添加职责,不需要拘泥于编译时
类图角色和职责
装饰模式四种角色
抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类
装饰角色(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口
具体装饰角色(ConcreteDecorator):负责给构件对象“贴上”附加的责任
装饰模式的优缺点
优点
被装饰者和装饰者是松耦合关系。由于装饰(Decorator)仅仅依赖于抽象组件(Component),因此具体装饰只知道它要装饰的对象是抽象组件的某一个子类的实例,但不需要知道是哪一个具体子类。
装饰模式满足“开-闭原则”。不必修改具体组件,就可以增加新的针对该具体组件的具体装饰。
可以使用多个具体装饰来装饰具体组件的实例。
缺点
装饰模式比继承更加灵活机动的特性,也同时意味着更加多的复杂性。装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出较佳选择。
案例
适用于:
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。不改变接口的前提下,增强所考虑的类的性能。
何时使用:
1)需要扩展一个类的功能,或给一个类增加附加责任。
2)需要动态的给一个对象增加功能,这些功能可以再动态地撤销。
3)需要增加一些基本功能的排列组合而产生的非常大量的功能,从而使继承变得 不现实。
装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。
简单案例:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
/*装饰模式*/
//一般情况下 用继承实现类的功能拓展
//装饰模式 可以动态的给一个类增加功能
class AbstractHero{
public:
virtual void showStatus() = 0;
public:
int mHp; //血量
int mMp; //能量
int mAt; //攻击
int mDf; //防御
};
//具体的英雄
class HeroA : public AbstractHero{
public:
HeroA(){
mHp = 0; //血量
mMp = 0; //能量
mAt = 0; //攻击
mDf = 0; //防御
}
virtual void showStatus(){
cout << "血量:" << mHp << endl;
cout << "能量:" << mMp << endl;
cout << "攻击:" << mAt << endl;
cout << "防御:" << mDf << endl;
}
};
//装饰类
class VirtualEquipment:public AbstractHero{
public:
VirtualEquipment(AbstractHero* hero){
this->hero = hero;
}
virtual void showStatus(){}
public:
AbstractHero* hero;
};
//穿上服饰
class ClothEquipment :public VirtualEquipment{
public:
ClothEquipment(AbstractHero* hero) : VirtualEquipment(hero){};
void addCloth(){
this->mHp = this->hero->mHp; //血量
this->mMp = this->hero->mMp; //能量
this->mAt = this->hero->mAt; //攻击
this->mDf = this->hero->mDf + 30; //穿上服饰,防御值增加
delete this->hero;
}
virtual void showStatus(){
addCloth();
cout << "英雄穿上服饰后...." << endl;
cout << "血量:" << mHp << endl;
cout << "能量:" << mMp << endl;
cout << "攻击:" << mAt << endl;
cout << "防御:" << mDf << endl;
}
};
//配上匕首
class KnifeEquipment :public VirtualEquipment{
public:
KnifeEquipment(AbstractHero* hero) : VirtualEquipment(hero){};
void addKnife(){
this->mHp = this->hero->mHp; //血量
this->mMp = this->hero->mMp; //能量
this->mAt = this->hero->mAt + 80; //攻击
this->mDf = this->hero->mDf; //穿上服饰,防御值增加
delete this->hero;
}
virtual void showStatus(){
addKnife();
cout << "英雄配上匕首后...." << endl;
cout << "血量:" << mHp << endl;
cout << "能量:" << mMp << endl;
cout << "攻击:" << mAt << endl;
cout << "防御:" << mDf << endl;
}
};
void test(){
AbstractHero* hero = new HeroA;
hero->showStatus();
cout << "==================" << endl;
hero = new ClothEquipment(hero);
hero->showStatus();
cout << "==================" << endl;
hero = new KnifeEquipment(hero);
hero->showStatus();
}
int main(void){
test();
return 0;
}