(C++)设计模式------装饰者模式 decorator

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

装饰者模式(开放关闭原则: 对扩展开放,对修改关闭)

定义:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

这里用到了继承又用到了组合,继承的作用在于:达到“类型匹配”,而不是简单的利用继承获取到“行为”。如果我们以来继承的,那么类的行为只能在编译的时候静态的决定,换句话说就是行为如果不是来自超类就是子类覆盖后的版本,反之,利用组合可以吧装饰者混合着用  而且是在“运行时”。

 

意图:动态的给一个对象添加职责;即提供了“即插即用”方法,不用重新编译已有部分。

问题:要使用的对象将执行所需的基本功能。但是,可能需要为这个对像添加某些功能,这些附加的功能可能发生在对象的基本功能之前或之后。

解决方案:可以无需创建子类而扩展一个对象的功能

优点:类的层次结构大小和复杂度有了很大程度的降低

缺点:

1)如果装饰者本身是被装饰的,那么访问装饰模式中引进的特性将是非常困难的甚至是危险的。

2)系统对装饰者的使用顺序是敏感的。

附:显然,如果要更改被装饰者的基本功能的情况是不能用装饰者模式的。

 

·装饰者和被装饰者对象有相同的超类型

·你可以用一个或多个装饰者包装一个对象

·既然装饰者和被装饰者对象有相同的超类型,所以,在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。

·装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。

·对象可以在任何时候被装饰,所以,可以在运行时动态的不限量的用你喜欢的装饰者来装饰对象。


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


星巴兹(StarBuzz)咖啡:
最初的类设计为下边这个样子:


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


StarBuzz.h:

  1#ifndef __STARBUZZ_H__
  2#define __STARBUZZ_H__
  3
  4#include <atlstr.h>
  5#include <iostream>
  6using namespace std;
  7
  8#ifdef UNICODE
  9#define cout wcout
 10#endif
 11
 12
 13//定义父类
 14class CBeverage
 15{
 16public:
 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    }
 37protected:
 38    CString m_description;
 39    float m_cost;
 40};
 41
 42//定义咖啡类1
 43class CHouseBlend : public CBeverage
 44{
 45public:
 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//定义咖啡类2
 68class CDarkRoast : public CBeverage
 69{
 70public:
 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//定义咖啡类3
 93class CEspresso : public CBeverage
 94{
 95public:
 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//定义咖啡类4
118class CDecaf : public CBeverage
119{
120public:
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//定义调料类
144class CCondiment : public CBeverage
145{
146public:
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;
162protected:
163    CBeverage* m_pbeverage;
164    CString m_description;
165    float m_cost;
166
167};
168
169
170//具体的调料1
171class CMilk : public CCondiment
172{
173public:
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//具体的调料2
197class CMocha : public CCondiment
198{
199public:
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//具体的调料3
223class CSoy : public CCondiment
224{
225public:
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//具体的调料4
250class CWhip : public CCondiment
251{
252public:
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#endif

Test:
 1// StarBuzz-DecoratePatten.cpp : Defines the entry point for the console application.
 2//
 3
 4#include "stdafx.h"
 5#include "StarBuzz.h"
 6
 7
 8int _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
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值