装饰者模式(开放关闭原则: 对扩展开放,对修改关闭)
定义:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
这里用到了继承又用到了组合,继承的作用在于:达到“类型匹配”,而不是简单的利用继承获取到“行为”。如果我们以来继承的,那么类的行为只能在编译的时候静态的决定,换句话说就是行为如果不是来自超类就是子类覆盖后的版本,反之,利用组合可以吧装饰者混合着用 而且是在“运行时”。
意图:动态的给一个对象添加职责;即提供了“即插即用”方法,不用重新编译已有部分。
问题:要使用的对象将执行所需的基本功能。但是,可能需要为这个对像添加某些功能,这些附加的功能可能发生在对象的基本功能之前或之后。
解决方案:可以无需创建子类而扩展一个对象的功能
优点:类的层次结构大小和复杂度有了很大程度的降低
缺点:
1)如果装饰者本身是被装饰的,那么访问装饰模式中引进的特性将是非常困难的甚至是危险的。
2)系统对装饰者的使用顺序是敏感的。
附:显然,如果要更改被装饰者的基本功能的情况是不能用装饰者模式的。
·装饰者和被装饰者对象有相同的超类型
·你可以用一个或多个装饰者包装一个对象
·既然装饰者和被装饰者对象有相同的超类型,所以,在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。
·装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
·对象可以在任何时候被装饰,所以,可以在运行时动态的不限量的用你喜欢的装饰者来装饰对象。

在上图中,让Decorator继承自Component并不是要继承Component的行为,而是因为装饰者与被装饰者必须是一样的类型(这样装饰者才能取代被装饰者),这是相当关键的地方。在这里,我们利用继承达到“类型匹配”而不是利用继承获得行为。
而装饰者的行为是如何加入的呢?将装饰者与组建组合时,就是在加入行为。所得到的新行为,并不是来自继承,而是由组合对象得来的。
星巴兹(StarBuzz)咖啡:
最初的类设计为下边这个样子:

但是,当顾客需要加调料时怎么办呢?如果将加了某种调料的咖啡设计成另外一个类,那么将引起类爆炸。我们采用如下的做法:以饮料为主体,然后在运行时以调料来装饰(decorate)饮料。

StarBuzz.h:
#ifndef __STARBUZZ_H__2
#define __STARBUZZ_H__3

4
#include <atlstr.h>5
#include <iostream>6
using namespace std;7

8
#ifdef UNICODE9
#define cout wcout10
#endif11

12

13
//定义父类14
class CBeverage15


{16
public:17
CBeverage()18

{19
m_description = _T("Unknow Beverage");20
m_cost = 0.0F;21
}22

23
virtual ~CBeverage()24

{25
cout << _T("~CBeverage") << endl;26
}27

28
virtual CString GetDescription()29

{30
return m_description;31
}32

33
virtual float GetCost()34

{35
return m_cost;36
}37
protected:38
CString m_description;39
float m_cost;40
};41

42
//定义咖啡类143
class CHouseBlend : public CBeverage44


{45
public:46
CHouseBlend()47

{48
m_description = _T("HouseBlend");49
m_cost = 2.4F;50
}51

52
~CHouseBlend()53

{54
cout << _T("~CHouseBlend") << endl;55
}56

57
virtual CString GetDescription()58

{59
return m_description;60
}61
virtual float GetCost()62

{63
return m_cost;64
}65
};66

67
//定义咖啡类268
class CDarkRoast : public CBeverage69


{70
public:71

CDarkRoast()/**//*:m_description(_T("HouseBlend")),m_cost(6)*/72

{73
m_description = _T("DarkRoast");74
m_cost = 2.4F;75
}76
77
~CDarkRoast()78

{79
cout << _T("~CDarkRoast") << endl;80
}81

82
virtual CString GetDescription()83

{84
return m_description;85
}86
virtual float GetCost()87

{88
return m_cost;89
}90
};91

92
//定义咖啡类393
class CEspresso : public CBeverage94


{95
public:96
CEspresso()97

{98
m_description = _T("Espresso");99
m_cost = 2.4F;100
}101

102
~CEspresso()103

{104
cout << _T("~CEspresso") << endl;105
}106

107
virtual CString GetDescription()108

{109
return m_description;110
}111
virtual float GetCost()112

{113
return m_cost;114
}115
};116

117
//定义咖啡类4118
class CDecaf : public CBeverage119


{120
public:121
CDecaf()122

{123
m_description = _T("Decaf");124
m_cost = 2.4F;125
}126

127
~CDecaf()128

{129
cout << _T("~CDecaf") << endl;130
}131

132
virtual CString GetDescription()133

{134
return m_description;135
}136
virtual float GetCost()137

{138
return m_cost;139
}140
};141

142

143
//定义调料类144
class CCondiment : public CBeverage145


{146
public:147
CCondiment()148

{149
m_pbeverage = NULL;150
m_description = _T("Unknow Condiment");151
m_cost = 0.0F;152
}153
~CCondiment()154

{155
//这样做不好,因为m_pbeverage所占的内存并不是在这个类中分配的.156
//不过,如果不这么做,那么在使用的时候会出现泄露157
delete m_pbeverage;158
cout << _T("~CCondiment") << endl;159
}160
virtual CString GetDescription() = 0;161
virtual float GetCost() = 0;162
protected:163
CBeverage* m_pbeverage;164
CString m_description;165
float m_cost;166

167
};168

169

170
//具体的调料1171
class CMilk : public CCondiment172


{173
public:174
CMilk(CBeverage* pbev)//注意,这里是指针175

{176
m_pbeverage = pbev;177
m_description = _T("Milk");178
m_cost = 2.4F;179
}180

181
~CMilk()182

{183
cout << _T("~CMilk") << endl;184
}185

186
CString GetDescription()187

{188
return m_pbeverage->GetDescription() + _T(",") + m_description; 189
}190
float GetCost()191

{192
return m_pbeverage->GetCost() + m_cost;193
}194
};195

196
//具体的调料2197
class CMocha : public CCondiment198


{199
public:200
CMocha(CBeverage* pbev)201

{202
m_pbeverage = pbev;203
m_description = _T("Mocha");204
m_cost = 2.5F;205
}206

207
~CMocha()208

{209
cout << _T("~CMocha") << endl;210
}211

212
CString GetDescription()213

{214
return m_pbeverage->GetDescription() + _T(",") + m_description; 215
}216
float GetCost()217

{218
return m_pbeverage->GetCost() + m_cost;219
}220
};221

222
//具体的调料3223
class CSoy : public CCondiment224


{225
public:226
CSoy(CBeverage* pbev)227

{228
229
m_pbeverage = pbev;230
m_description = _T("Soy");231
m_cost = 2.6F; 232
}233

234
~CSoy()235

{236
cout << _T("~CSoy") << endl;237
}238

239
CString GetDescription()240

{241
return m_pbeverage->GetDescription() + _T(",") + m_description; 242
}243
float GetCost()244

{245
return m_pbeverage->GetCost() + m_cost;246
}247
};248

249
//具体的调料4250
class CWhip : public CCondiment251


{252
public:253
CWhip(CBeverage* pbev)254

{255
256
m_pbeverage = pbev;257
m_description = _T("Whip");258
m_cost = 2.7F; 259
}260

261
~CWhip()262

{263
cout << _T("~CWhip") << endl;264
}265

266
CString GetDescription()267

{268
return m_pbeverage->GetDescription() + _T(",") + m_description; 269
}270
float GetCost()271

{272
return m_pbeverage->GetCost() + m_cost;273
}274
};275
#endifTest:
// StarBuzz-DecoratePatten.cpp : Defines the entry point for the console application.2
//3

4
#include "stdafx.h"5
#include "StarBuzz.h"6

7

8
int _tmain(int argc, _TCHAR* argv[])9


{10
CBeverage* pbeverage = new CHouseBlend();11
pbeverage = new CMilk(pbeverage);12
pbeverage = new CSoy(pbeverage);13
pbeverage = new CWhip(pbeverage);14
pbeverage = new CMocha(pbeverage);15

16
cout << (LPCTSTR)pbeverage->GetDescription() << _T(": ")<< pbeverage->GetCost() << endl;17

18
delete pbeverage;19

20
return 0;21
}22

23


本文介绍装饰者模式的应用原理与实现方式,通过星巴兹咖啡的例子详细解释如何动态地为对象添加职责,避免类爆炸的同时保持代码的灵活性。
9342

被折叠的 条评论
为什么被折叠?



