08:装饰者模式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012424148/article/details/84841724

一、介绍

 

    装饰器模式(Decorator Pattern允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

 

二、应用场景

1. 需要扩展一个类的功能,或给一个类添加附加职责。

2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。

3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。

4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

 

三、要点

1. 多组合,少继承。

利用继承设计子类的行为,是在编译时静态决定的,而且所有的子类都会继承到相同的行为。然而,如果能够利用组合的做法扩展对象的行为,就可以在运行时动态地进行扩展。

2. 类应设计的对扩展开放,对修改关闭。

 

 

四、样例

在星巴克购买咖啡时,可以要求在其中加入各种调味品(辅料)。调味品很多,有些不收费(例如:白砂糖、香草粉等),有些则需要额外收费(例如:奶油、摩卡、糖浆等),所以充分利用起来吧!倘若咖啡不带劲,我们想要添加奶油、摩卡和糖浆,这时,就可以利用装饰者模式思想来实现。

 

1、创建构建

先定义所有饮料基类,并提供名称和价钱

// component.h
#ifndef COMPONENT_H
#define COMPONENT_H

#include <string>
using namespace std;

class IBeverage
{
public:
	virtual string Name() = 0;
	virtual double Cost() = 0;
};

#endif

2、创建具体构建

// concrete_component.h
#ifndef CONCRETE_COMPONENT_H
#define CONCRETE_COMPONENT_H

#include "component.h"

/******** 具体饮料(咖啡) ********/
// 黑咖啡
class HouseBlend :public Ibeverage
{
public:
	string Name()
	{
		return "HouseBlend";
	}

	double Cost()
	{
		return 30.0;
	}
};

// 深度烘焙咖啡
class DarkRoast :public IBeverage
{
public:
	string Name()
	{
		return "DarkRoast";
	}

	double Cost()
	{
		return 28.5
	}
};
#endif

3、创建装饰

咖啡有了,剩下的就是添加调味品,其同样继承IBeverage,并持有咖啡的实例

// decorator.h
#ifndef DECORATOR_H
#define DECORATOR_H

#include "component.h"

// 调味品
class CondimentDecorator :public IBeverage
{
public:
	CondimentDecorator(IBeverage *beverage) :m_pBeverage(beverage) {}

	string Name()
	{
		return m_pBeverage->Name();
	}

	double Cost()
	{
		return m_pBeverage->Cost();
	}

protected:
	IBeverage *m_pBeverage;

};
#endif

4、创建具体装饰

// concrete_decorator.h
#ifndef CONCRETE_DECORATOR_H
#define CONCRETE_DECORATOR_H

#include "decorator.h"

/***** 具体的饮料(调味品) ******/

// 奶油
class Cream : public CondimentDecorator
{
public:
	Cream(IBeverage *beverage) : CondimentDecorator(beverage) {}

	string Name()
	{
		return m_pBeverage->Name() + " Cream";
	}

	double Cost()
	{
		return m_pBeverage->Cost() + 3.5;
	}
};

// 摩卡
class Mocha : public CondimentDecorator
{
public:
	Mocha(IBeverage *beverage) : CondimentDecorator(beverage) {}

	string Name()
	{
		return m_pBeverage->Name() + " Mocha";
	}

	double Cost()
	{
		return m_pBeverage->Cost() + 2.0;
	}
};

// 糖浆
class Syrup :public CondimentDecorator
{
public:
	Syrup(IBeverage *beverage) :CondimentDecorator(beverage) {}

	string Name()
	{
		return m_pBeverage->Name() + " Syrup";
	}

	double Cost()
	{
		return m_pBeverage->Cost() + 3.0;
	}
};

#endif

5、创建客户端

// main.cpp
#include "concrete_component.h"
#include "concrete_decorator.h"
#include <iostream>

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){ delete(p); (p) = NULL; } }
#endif

int main()
{
	/***** 黑咖啡 *******/
	IBeverage *pHouseBlend = new HouseBlend();
	cout << pHouseBlend->Name() << ":" << pHouseBlend->Cost() << endl;

	// 黑咖啡+奶油
	CondimentDecorator *pCream = new Cream(pHouseBlend);
	cout << pCream->Name() << ":" << pCream->Cost() << endl;

	// 黑咖啡+摩卡
	CondimentDecorator *pMocha = new Mocha(pHouseBlend);
	cout << pMocha->Name() << ":" << pMocha->Cost() << endl;

	// 黑咖啡+糖浆
	CondimentDecorator *pSyrup = new Syrup(pHouseBlend);
	cout << pSyrup->Name() << ":" << pSyrup->Cost() << endl;

	/******* 深度烘焙咖啡 ********/
	IBeverage *pDarkRoast = new DarkRoast();
	cout << pDarkRoast->Name() << ":" << pDarkRoast->Cost() << endl;

	// 深度烘焙+奶油
	CondimentDecorator *pCreamDR = new Cream(pDarkRoast);
	cout << pCreamDR->Name() << ":" << pCreamDR->Cost() << endl;

	// 深度烘焙+奶油+摩卡
	CondimentDecorator *pCreamMocha = new Mocha(pCreamDR);
	cout << pCreamMocha->Name() << ":" << pCreamMocha->Cost() << endl;

	// 深度烘焙+奶油+摩卡+糖浆
	CondimentDecorator *pCreamMochaSyrup = new Syrup(pCreamMocha);
	cout << pCreamMochaSyrup->Name() << ":" << pCreamMochaSyrup->Cost() << endl;

	SAFE_DELETE(pSyrup);
	SAFE_DELETE(pMocha);
	SAFE_DELETE(pCream);
	SAFE_DELETE(pHouseBlend);

	SAFE_DELETE(pCreamMochaSyrup);
	SAFE_DELETE(pCreamMocha);
	SAFE_DELETE(pCreamDR);
	SAFE_DELETE(pDarkRoast);

	getchar();
	return 0;
}

6、输出

HouseBlend Cream : 33.5
HouseBlend Mocha : 32
HouseBlend Syrup : 33
DarkRoast : 28.5
DarkRoast Cream : 32
DarkRoast Cream Mocha : 34
HouseBlend : 30
DarkRoast Cream Mocha Syrup : 37

五、优缺点

优点

1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。

2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

 

缺点

1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。

2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。

3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

 

猜你喜欢

转载自blog.csdn.net/u012424148/article/details/84841724
今日推荐