在面对对象编程的时候大家都知道应该多用组合,而非继承。今天我们学习的这个模式便会给我们喜欢继承的小伙伴们一个全新的设计方式。
首先大家考虑这么一个问题,我们每天早上起来穿衣服这件事。身为一个程序猿我们一定要学会自己爱惜自己,尤其是到了冬天,我们都喜欢里三层、外三层,生怕冻着自己。
就以我自己为例,为了表示对冬天最起码的尊重,首先我会先穿一件秋衣,在秋衣外面我喜欢再套一件毛衣或者卫衣,穿好毛衣后我一般还会套一个褂子,你以为这就完了?哼,那你就是太看不起北京的冬天了,最外面一般我还会穿一件厚厚的羽绒服,只有把自己裹得跟一个球一样我才能感觉到一点点的温暖。
可能有些小伙伴看到这里懵圈了,我是来学设计模式的,你给我扯这一堆没用的干嘛。
那现在大家就穿衣服这件事考虑一个问题,我们每次在穿好上一件衣服穿下一件衣服的过程中,是否之前穿的衣服对后来有影响?
假如我还需要在外面穿更多的衣服,是否需要对里面穿的衣服做出调整呢?(不考虑衣服大小,无论多大我都能套进去。)。
我每件衣服的作用是否又都发挥了呢?
可能有些小伙伴看到这里有些意思了,好了,接下来我们看一下装饰者模式的定义吧!
装饰者模式:动态的将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的代替方案。
接下来我们看一下用代码应该如何实现。
#include <iostream>
#include <memory>
using namespace std;
class CPersonBass //人,我的基类
{
public:
CPersonBass() = default;
virtual ~CPersonBass() {};
virtual void goOut() = 0;
};
class CWinterMe :public CPersonBass//冬天的我
{
public:
CWinterMe() = default;
~CWinterMe() {};
void goOut()
{
cout << "外面零下十度,我要出门了!"<<endl;
}
};
//衣服的基类,有些人可能对这里有点疑惑了,没错,这里我们是使用了继承,但是我们的继承只是为了类型匹配,而不是实现一个人
class CClothesBase :public CPersonBass
{
public:
CClothesBase(shared_ptr<CPersonBass> person)
{
m_person = person;
}
virtual void used() = 0;
virtual void goOut()
{
m_person->goOut();
used();
}
protected:
shared_ptr<CPersonBass> m_person;
};
class CAutumnClothes :public CClothesBase //秋衣
{
public:
CAutumnClothes(shared_ptr<CPersonBass> person) :CClothesBase(person) {}
~CAutumnClothes(){}
void used()
{
cout << "穿上了秋衣,为了表达对冬天的尊重!"<<endl;
}
};
class CSweater :public CClothesBase//毛衣
{
public:
CSweater(shared_ptr<CPersonBass> person) :CClothesBase(person) {}
~CSweater() {}
void used()
{
cout << "穿上了毛衣,有点温暖的感觉!" << endl;
}
};
class CCoat :public CClothesBase//毛衣
{
public:
CCoat(shared_ptr<CPersonBass> person) :CClothesBase(person) {}
~CCoat() {}
void used()
{
cout << "穿上了外套,还是冷!" << endl;
}
};
class CDownJacket :public CClothesBase//毛衣
{
public:
CDownJacket(shared_ptr<CPersonBass> person) :CClothesBase(person) {}
~CDownJacket() {}
void used()
{
cout << "穿上了羽绒服,总算暖和了!" << endl;
}
};
int main()
{
shared_ptr<CPersonBass> me = make_shared<CWinterMe>();//冬天的我
shared_ptr<CPersonBass> MeOfAutumn = make_shared<CAutumnClothes>(me);//穿上秋衣的我
shared_ptr<CPersonBass> MeOfSweater = make_shared<CSweater>(MeOfAutumn);//穿上毛衣的我
shared_ptr<CPersonBass> MeOfCoat = make_shared<CCoat>(MeOfSweater);//穿上外套的我
shared_ptr<CPersonBass> MeOfJacket = make_shared<CDownJacket>(MeOfCoat);//穿上羽绒服的我
MeOfJacket->goOut();
return 0;
}
输出结果:
外面零下十度,我要出门了!
穿上了秋衣,为了表达对冬天的尊重!
穿上了毛衣,有点温暖的感觉!
穿上了外套,还是冷!
穿上了羽绒服,总算暖和了!
说到这里可能有些小伙伴已经看出来了,为了使用我们的装饰者模式,我们创建了很多小的类,对,这一点便是使用策略模式的缺点,接下来我们总结一下今天所学吧。
以下十点摘自《Head First 设计模式》
- 继承属于扩展形式之一,但不见得是达到弹性设计的最佳方式。
- 在我们的设计中,应该允许行为可以被扩展,而无需修改现有代码。
- 组合和委托可用于在运行时动态的加上新的行为。
- 除了继承,装饰者模式也可以让我们扩展行为。
- 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。
- 装饰者类反映出被装饰的组件。
- 装饰者可以在被装饰者的行为前面或后面加上自己的行为,甚至将被装饰者的行为这个取代掉,而达到特定的目的。
- 你可以使用无数个装饰者包装一个组件。
- 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。
- 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。