现在的位置: 首页 > 综合 > 正文

HeadFirst设计模式 之 C++实现(三):Decorator(装饰者模式)

2018年11月08日 ⁄ 综合 ⁄ 共 4192字 ⁄ 字号 评论关闭

装饰者模式是很有意思的一种设计模式,你将能够在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。不是使用继承每回在编译时超类上修改代码,而是利用组合(composition)和委托(delegation)可以在运行时具有继承行为的效果。

代码应该如同晚霞中的莲花一样地关闭(免于改变),如同晨曦中的莲花一样地开放(能够扩展)。

这就是,设计原则之五:类应该对扩展开放,对修改关闭

通常情况下,我们不会对代码的每一处设计都采用该原则,我们实在没有闲工夫把设计的每个部分都这么设计(而且,就算做得到,也可能只是一种浪费)。你需要把注意力集中在设计中最有可能改变的地方,然后应用开放-关闭原则


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

当然,这并不代表我们在设计类的时候不采用继承,装饰者和被装饰者必须是一样的类型,也就是有共同的超类,这是相当关键的地方。在这里,我们利用继承达到“类型匹配”,而不是利用继承获得“行为”。如果依赖继承,那么类的行为只能在编译时静态决定。换句话说,行如果不是来自超类,就是子类覆盖后的版本。反之,利用组合,可以把装饰者混合着用……而且是在“运行时”。

下面我们来看星巴兹饮料的设计方案,四种饮料可以分别和不同数量不同种类的调料搭配起来销售给客户:


装饰者通常是用其他类似于工厂或生成器这样的模式创建的。组合和委托可用于在运行时动态地加上新的行为。

然后是我自己用C++实现的星巴兹饮料模型(在实现中,我加入了:在菜单上加上咖啡的容量大小供客户选择,因此也需要考虑调料根据咖啡容量收费),有疏漏的地方请指教:

// Decorator Patterm(装饰者设计模式)
#include <iostream>
#include <string>
enum SIZE{Tall_SIZE, GRANDE_SIZE, RENTI_SIZE};
using std::string;

// 超类,ABC,抽象组件
class Beverage
{
public:
	Beverage();
	virtual ~Beverage();
	int getSize();		// 在实现饮料搭配调料的基础上,添加的新功能
	void setSize(int sizeOfBeverge);	// 可以自主选择大中小杯,当然,价格也不一样哦~
	virtual string & getDescription() = 0;
	virtual float cost() = 0;
protected:
	string m_description;
private:
	SIZE m_size;
};

// 装饰类,抽象装饰
class CondimentDecorator : public Beverage
{
public:
	virtual string & getDescription();
};

// 具体的咖啡,继承自超类,具体组件
class Espresso : public Beverage
{
public:
	Espresso();
	float cost();
};

class HouseBlend : public Beverage
{
public:
	HouseBlend();
	float cost();
};
// 另外两种饮料类(DarkRoast和Decaf)都是一样的

// 调料,具体装饰
class Mocha : public CondimentDecorator
{
private:
	Beverage *m_beverage;
public:
	Mocha(Beverage * beverage);
	string & getDescription();
	float cost();
};

class Whip : public CondimentDecorator
{
private:
	Beverage *m_beverage;
public:
	Whip(Beverage * beverage);
	string & getDescription();
	float cost();
};

DECORATOR—Mary过完轮到Sarly过生日,还是不要叫她自己挑了,不然这个月伙食费肯定玩完,拿出我去年在华山顶上照的照片,在背面写上“最好的的礼物,就是爱你的Fita”,再到街上礼品店买了个像框(卖礼品的MM也很漂亮哦),再找隔壁搞美术设计的Mike设计了一个漂亮的盒子装起来……我们都是Decorator,最终都在修饰我这个人呀,怎么样,看懂了吗?


  装饰模式:装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。

// Decorator Patterm(装饰者设计模式)

#include "DecoratorPattern.h"

// 超类,ABC,抽象组件
Beverage::Beverage()
{
	this->m_description = "Unknow Beverage";
	m_size = RENTI_SIZE;
}

Beverage::~Beverage()
{
}

string & Beverage::getDescription()
{
	return m_description;
}

int Beverage::getSize()
{
	return m_size;
}

// 输入0 - Tall_SIZE小杯,输入1 - GRANDE_SIZE中杯
// 输入2 - RENTI_SIZE,输入others - 默认RENTI_SIZE大杯 
void Beverage::setSize(int sizeOfBeverge)
{
	switch(sizeOfBeverge)
	{
		case Tall_SIZE:
			m_size = Tall_SIZE;
			break;
		case GRANDE_SIZE:
			m_size = GRANDE_SIZE;
			break;
		case RENTI_SIZE:
		default:
			m_size = RENTI_SIZE;
			break;
	}
}
// CondimentDecorator没有什么好实现的,构造和析构都用默认

// 具体的咖啡,继承自超类,具体组件
Espresso::Espresso()
{
	m_description = "Espresso Coffee";
}

float Espresso::cost()
{
	double allCost;
	switch(getSize())
	{
		case Tall_SIZE:
			allCost = 1.0;
			break;
		case GRANDE_SIZE:
			allCost = 1.5;
			break;
		case RENTI_SIZE:
		default:
			allCost = 1.9;
			break;
	}
	return allCost;
}

HouseBlend::HouseBlend()
{
	m_description = "HouseBlend Coffee";
}

float HouseBlend::cost()
{
	double allCost;
	switch(getSize())
	{
		case Tall_SIZE:
			allCost = .4;
			break;
		case GRANDE_SIZE:
			allCost = .7;
			break;
		case RENTI_SIZE:
		default:
			allCost = .89;
			break;
	}
	return allCost;
}

// 调料,具体的装饰类
Mocha::Mocha(Beverage * beverage)
{
	m_beverage = beverage;
}

string & Mocha::getDescription()
{
	return m_beverage->getDescription() + ", Mocha";
}

float Mocha::cost()
{	
	double allcost = m_beverage->cost();
	switch(m_beverage->getSize())
	{
		case Tall_SIZE:
			allcost += .10;
			break;
		case GRANDE_SIZE:
			allcost += .15;
			break;
		case RENTI_SIZE:
		default:
			allcost += .20;
			break; 
	}
	return allcost;
}

Whip::Whip(Beverage * beverage)
{
	m_beverage = beverage;
}

string & Whip::getDescription()
{
	return m_beverage->getDescription() + ", Whip";
}

float Whip::cost()
{
	double allcost = m_beverage->cost();
	switch(m_beverage->getSize())
	{
		case Tall_SIZE:
			allcost += .15;
			break;
		case GRANDE_SIZE:
			allcost += .20;
			break;
		case RENTI_SIZE:
		default:
			allcost += .25;
			break; 
	}
	return allcost;
}


我们比方说,如果顾客想要双倍摩卡奶泡深焙咖啡中杯,实现如下(图表示的是摩卡和奶泡深焙咖啡的包含装饰结构):

<pre name="code" class="cpp">
int main()
{
	// 双倍摩卡奶泡深焙咖啡中杯
	Beverage * beverage1 = new Espresso();
	beverage1->setSize(GRANDE_SIZE);
	beverage1 = new Mocha(beverage1);
	beverage1 = new Mocha(beverage1);
	beverage1 = new Whip(beverage1);
	
	delete beverage1;
	return 0;
}



我相信大家都有用过PS,而且都了解过PS中图层的原理,当我们P图片时候使用图层可以实现很多效果,而且如果我们觉得其中一个图层效果不好看我们可以直接删除,而不影响其他图层,我们每次P出来的照片都是一层层图层的叠加得到的。这也是装饰者的一种可应用场景。

当然,装饰者模式也有缺点:

1、 装饰链不能过长,否则会影响效率。

2、只在必要的时候使用装饰者模式,装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂,增加系统维护难度。


转载请注明出处:http://blog.csdn.net/aall3210_tsingloon/article/details/28870771


抱歉!评论已关闭.