设计模式——装饰者模式(c++)

装饰者模式用来解决的问题是:主体类(例如,下文中的各种咖啡)有多种装饰属性(例如,下文中的milk,whip等),而且装饰属性可以任意组合叠加,如果通过继承主体类来添加属性,子类的数量将非常庞大,不易维护。

装饰者模式的核心在于——用“组合”代替“继承”!如果依赖继承,类的行为只能在编译时静态决定。但是利用组合,再加上多态,就可以使类的行为在运行是动态决定,提高了代码的可复用性。

在GOF《设计模式》中将装饰者模式定义为:动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,装饰者模式比生成子类(继承)更为灵活(消除重复代码&减少子类个数)。

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

装饰者模式遵守开闭原则——“对扩展开放,对修改关闭”。也就是说,可以实现在不修改类的同时,对类进行扩展。

装饰者模式中,同时使用了继承和组合两种方式,这是比较特殊的地方(一般来讲,继承和组合是不同时使用的)。装饰者模式中,利用继承达到“类型匹配”,而不是“继承行为”。

下面通过一个例子来说明装饰者模式(来自《HeadFirst设计模式》,将其用c++实现)。

一个咖啡店的点单系统中,有多种咖啡:HouseBlend、DarkRoast、Defaf、Espresso...,购买咖啡时,顾客还可能要求加入各种配料:Milk、Soy、Mocha、Whip,顾客点单后需要根据所点的咖啡和配料计算出价格。此外,咖啡的种类和配料的种类随时可能增加,而且价格也随时可能会变化。下面给出两种设计方案,并说明它们的优缺点。

方案一:利用继承来扩展。


从上面的类图可以看到,子类的数量将非常非常多,代码重复严重,修改和维护极为不便。

方案二:装饰者模式,用组合代替继承。

#ifndef BEVERAGE_H 
#define BEVERAGE_H
#include <string>
using std::string;

class Beverage {
public:
Beverage(const string& describe,int cost):m_describe(describe),m_cost(cost){}
virtual ~Beverage() {}
virtual string getDescribe() const { return m_describe; }
virtual int getCost() const { return m_cost; }
protected:
string m_describe;
int m_cost;
};

class HouseBlend:public Beverage {
public:
HouseBlend(const string& describe="It is a cup of HouseBlend", int cost=100) :Beverage(describe, cost) {}
};
class DarkRoast:public Beverage {
public:
DarkRoast(const string& describe = "It is a cup of DarkRoast", int cost=200) :Beverage(describe, cost) {}
};
class Espresso :public Beverage{
public:
Espresso(const string& describe = "It is a cup of Espresso", int cost=300) :Beverage(describe, cost) {}
};
class Decaf :public Beverage {
public:
Decaf(const string& describe = "It is a cup of Decaf", int cost = 400) :Beverage(describe, cost) {}
};
#endif


#ifndef DECORATOR_H
#define DECORATOR_H
#include "Beverage.h"
#include <iostream>
using std::cout;
using std::endl;
 
class Decorator :public Beverage {
public:
virtual ~Decorator() {}
Decorator(Beverage *pBeverage,string describe, int cost) :Beverage(describe, cost), m_pBeverage(pBeverage) {}
virtual string getDescribe() const { return m_pBeverage->getDescribe() + "+" + m_describe; }
virtual int getCost() const { return m_pBeverage->getCost() + m_cost; }
private:
Beverage *m_pBeverage;
};

class Milk :public Decorator{
public:
Milk(Beverage *pBeverage, const string& describe="Milk", int cost=1) :Decorator(pBeverage, describe, cost) {}
};

class Mocha :public Decorator {
public:
Mocha(Beverage *pBeverage, const string& describe="Mocha", int cost=2) :Decorator(pBeverage, describe, cost) {}
};

class Soy :public Decorator {
public:
Soy(Beverage *pBeverage, const string& describe="Soy", int cost=3) :Decorator(pBeverage, describe, cost) {}
};

class Whip :public Decorator {
public:
Whip(Beverage *pBeverage, const string& describe="Whip", int cost=4) :Decorator(pBeverage, describe, cost) {}
};
#endif


#include "Decorator.h"
#include "Beverage.h"
#include <iostream>
#include <string>

using std::cout;
using std::endl;
using std::string;

int main() {
Beverage *pB1 = new Whip(new Mocha(new Espresso()));
cout << pB1->getDescribe() << endl;
cout<< "$" << pB1->getCost()<<endl;
system("pause");
return 1;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值