Head First 设计模式——装饰者模式(Decorator Pattern)

本文介绍了如何运用装饰者模式解决星巴兹咖啡店订单系统的问题。通过装饰者模式,可以在运行时动态地为饮料添加调料,避免类爆炸问题和因调料价格变动而频繁修改代码。装饰者和被装饰对象具有相同的基类型,允许层层装饰,并能灵活应对如双倍摩卡咖啡等需求,提供了一种比继承更具弹性的拓展方式。
摘要由CSDN通过智能技术生成

装饰者模式  

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


设计原则

类应该对拓展开放,对修改关闭


问题描述:

星巴兹咖啡店扩张速度太快了,准备更新订单系统,以合乎他们的饮料供应要求。购买咖啡的时候,可以要求加入各种调料,例如:蒸奶,豆浆,摩卡等,星巴兹会根据所加入的调料收去不同的费用,所以订单系统必须考虑到这些调料部分。


解决方案:

一、对每一种组合定义一种类型,由于组合数目太多,会导致类爆炸

二、利用实例变量和继承可以追踪这些调料



这个设计面临的问题:

1.调料价格改变会使我们改变现有代码;

2.一旦出现新的调料,我们就需要加上新的方法,并且改变超类中的cost()方法

3.以后可能会开发出新的饮料,对这些饮料而言(例如:冰茶),某些调料可能不合适,但在这个设计中,Tea子类扔将继承那些不合适的方法,例如加奶泡

4.万一顾客想要双倍摩卡咖啡,怎么办?

三、装饰者模式

采用不一样的做法,我们要以饮料为主体,然后在运行时以调料来装饰饮料,比方说顾客想要摩卡和奶泡咖啡,那么要做的就是

1.拿一个深焙咖啡对象,

2.以摩卡对象装饰它

3.以奶泡对象装饰它

4.调用cost()方法,并依赖委托将调料的价钱加上去


#include<iostream>
#include<string>
using namespace std;

//饮料类是一个虚类,有两个方法
// 其中cost 必须在子类中实现
class Beverage{
public:
	Beverage(){
		description = "Unknown Beverage" ;
	}
	virtual string getDescription(){
		return description;
	}
	virtual double cost() = 0;
	string description;
};
//实现一些饮料类,Esprsso 和 HouseBlend
class Espresso:public Beverage{
public:
	Espresso(){
		description = "Espresso";
	}
	double cost(){
		return 1.99;
	}
};
class HouseBlend:public Beverage{
public:
	HouseBlend(){
		description = "House Blend Coffee";
	}
	double cost(){
		return 0.89;
	}
};

// 调料类,也就是装饰者类,必须让CondimentDecorator能够
//取代Beverage,所以将其从Beverage 继承
class CondimentDecorator: public Beverage{
	virtual string getDescription() = 0;
};
/*
要让Mocha能够引用一个Beverage,做法如下:
(1)用一个实例变量记录饮料,也就是被装饰者
(2)想办法让被装饰者被记录到实例变量中,这里的做法是:
把饮料当做构造器的参数,再由构造器将此饮料记录在实例变量中
*/
class Mocha : public CondimentDecorator{
public:
	Mocha(Beverage *beverage){
		this->beverage = beverage;
	}
	string getDescription(){
		return beverage->getDescription() + " , Mocha";
	}
	double cost(){
		return 0.20 + beverage->cost();
	}
private:
	Beverage *beverage;
};
class Soy : public CondimentDecorator{
public:
	Soy(Beverage *beverage){
		this->beverage = beverage;
	}
	string getDescription(){
		return beverage->getDescription() + " , Soy";
	}
	double cost(){
		return 0.20 + beverage->cost();
	}
private:
	Beverage *beverage;
};

int main(){
	Beverage *beverage = new  Espresso();
	cout << beverage->getDescription() << "   $" <<beverage->cost() << endl; 
	/*
	Beverage beverage2 = new DarkRoast();
	beverage2 = new Macha(beverage2);
	beverage2 = new Macha(beverage2);
	beverage2 = new Whip(beverage2);
	cout << beverage2.getDescription() << "   $" << beverage.cost() << endl;
	*/
	Beverage *beverage3 = new HouseBlend();
	beverage3 = new Soy(beverage3);
	//双份的Mocha
	beverage3 = new Mocha(beverage3);
	beverage3 = new Mocha(beverage3);
	cout << beverage3->getDescription() << "   $" << beverage3->cost() << endl;
	delete beverage;
	delete beverage3;
}
运行结果:


总结:

装饰者和被装饰对象有相同的基类型,这样才能一层层修饰下去

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

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

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

但是装饰者会导致设计中出现很多小对象,如果过度使用,会让程序变得复杂


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值