设计模式系列(三)装饰者模式(Decorator Pattern)

设计模式系列(三)装饰者模式(Decorator Pattern)

 

    装饰者模式是指动态地将责任附加到对象上,而不必改变原类文件。对于扩展功能,装饰者模式提供了继承以外的另一种扩展对象功能的方式,不过装饰者模式比继承更加具有弹性。装饰者模式允许行为可以被扩展,而无须修改现有的代码。它使用组合和委托的方式来实现。

 

    装饰者模式的设计原则是:开放-关闭原则,即对扩展开放,对修改关闭以及多用组合,少用继承的原则。

 

    装饰者模式通常由一些基本的组件和装饰者组成,它的特点主要是:

 

(1) 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的引用(reference)。
(3) 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

(5) 设计者可以通过将各种各样的装饰者进行排列组合,得到不同的装饰结果,从而实现各种功能扩展。

 

   以下情况使用Decorator模式:


(1) 需要扩展一个类的功能,或给一个类添加附加职责。
(2) 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
(3) 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
(4) 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

 

    装饰者模式的优点:

 

(1)比继承具有更大的弹性和灵活性。

(2)设计者可以通过将各种各样的装饰者进行排列组合,得到不同的装饰结果,从而实现各种功能扩展。

(3)装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。

 

    装饰者模式的缺点:

 

(1) 装饰者模式由于需要一些组件和装饰者,所以会引入很多小类,从而增加程序的复杂性,让程序变得难以理解。

(2) 装饰者模式在实例化组件时比较复杂,需要一步步从基本功能到装饰者功能一层层包装,增加了代码的复杂性,不过这个问题可以使用工厂模式或生成器来解决。

(3) 装饰者模式是针对抽象组件类型编程,所以要清楚自己的设计是需要对抽象还是具体。

 

    在JAVA中,装饰者模式使用也很多,最为常见的就是IO流的功能实现就是通过装饰者模式实现的。在装饰模式中的各个角色有:


(1)抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
(2)具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
(3)装饰(Decorator)角色:持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。
(4)具体装饰(Concrete Decorator)角色:负责给构件对象添加上附加的责任。

 

    下面我们来看一个例子,这个例子包含三个文件,依次是:DecoratorPattern.h文件、DecoratorPattern.cpp文件以及DecoratorPatternTest.cpp文件。


// 装饰者模式

#ifndef DECORATOR
#define DECORATOR

#include <iostream>
#include <string>
#include <iomanip>

using std::string;
using std::cout;
using std::endl;
using std::fixed;
using std::setprecision;

typedef enum size{ TALL, GRANDE, VENTI }coffeeSize;

// 所有类的超类
class Beverage 
{
public:
	Beverage()
	{
		description = "Unknown Beverage";
		cs = GRANDE;
	}
	virtual ~Beverage(){}

	virtual string getDescription();
	virtual void setSize(coffeeSize cs);
	virtual coffeeSize getSize();
	virtual double cost() = 0;

	string description;
private:
	coffeeSize cs;
};

// 装饰者的抽象类
class CondimentDecorator : public Beverage
{
public:
	CondimentDecorator(){}
	virtual ~CondimentDecorator(){}
	virtual string getDescription() = 0;
};

// 被装饰者具体类1
class HouseBlend : public Beverage
{
public:
	HouseBlend() 
	{
		description = "House Blend Coffee";
	}

	double cost();
};

// 被装饰者具体类2
class DarkRoast : public Beverage
{
public:
	DarkRoast()
	{
		description = "Dark Roast Coffee";
	}

	double cost();
};

// 被装饰者具体类3
class Espresso : public Beverage
{
public:
	Espresso()
	{
		description = "Espresso";
	}

	double cost();
};

// 被装饰者具体类4
class Decaf : public Beverage
{
public:
	Decaf()
	{
		description = "Decaf Coffee";
	}

	double cost();
};

// 装饰者具体类1
class Milk : public CondimentDecorator 
{
public:
	Milk(Beverage* beverage) {
		this->beverage = beverage;
	}

	~Milk()
	{
		cout << "调用析构函数" << endl;
		if (beverage != NULL)
		{
			delete beverage;
			beverage = NULL;
		}
	}

	string getDescription();
	double cost();

	Beverage* beverage;
};

// 装饰者具体类2
class Mocha : public CondimentDecorator
{
public:
	Mocha(Beverage* beverage) {
		this->beverage = beverage;
	}

	~Mocha()
	{
		cout << "调用析构函数" << endl;
		if (beverage != NULL)
		{
			delete beverage;
			beverage = NULL;
		}
	}

	string getDescription();
	double cost();

	Beverage* beverage;
};

// 装饰者具体类3
class Soy : public CondimentDecorator
{
public:
	Soy(Beverage* beverage) {
		this->beverage = beverage;
	}

	~Soy()
	{
		cout << "调用析构函数" << endl;
		if (beverage != NULL)
		{
			delete beverage;
			beverage = NULL;
		}
	}

	string getDescription();
	double cost();

	Beverage* beverage;
};

// 装饰者具体类4
class Whip : public CondimentDecorator
{
public:
	Whip(Beverage* beverage) {
		this->beverage = beverage;
	}

	~Whip()
	{
		cout << "调用析构函数" << endl;
		if (beverage != NULL)
		{
			delete beverage;
			beverage = NULL;
		}
	}

	string getDescription();
	double cost();

	Beverage* beverage;
};

#endif


#include"DecoratorPattern.h"
 
// 所有类的超类
stringBeverage::getDescription()
{
        return description;
}
 
void Beverage::setSize(coffeeSizecs)
{
        this->cs = cs;
}
 
coffeeSizeBeverage::getSize()
{
        return cs;
}
 
// 被装饰者具体类1
doubleHouseBlend::cost()
{
        if (getSize() == TALL)
        {
               return 0.89;
        }
        else if (getSize() == GRANDE)
        {
               return 0.94;
        }
        else
        {
               return 0.99;
        }
}
 
// 被装饰者具体类2
doubleDarkRoast::cost()
{
        if (getSize() == TALL)
        {
               return 0.99;
        }
        else if (getSize() == GRANDE)
        {
               return 1.04;
        }
        else
        {
               return 1.09;
        }
}
 
// 被装饰者具体类3
doubleEspresso::cost()
{
        if (getSize() == TALL)
        {
               return 1.99;
        }
        else if (getSize() == GRANDE)
        {
               return 2.04;
        }
        else
        {
               return 2.09;
        }
}
 
// 被装饰者具体类4
double Decaf::cost()
{
        if (getSize() == TALL)
        {
               return 1.05;
        }
        else if (getSize() == GRANDE)
        {
               return 1.09;
        }
        else
        {
               return 1.14;
        }
}
 
// 装饰者具体类1
stringMilk::getDescription()
{
        return beverage->getDescription() +", Milk";
}
 
double Milk::cost()
{
        if (beverage->getSize() == TALL)
        {
               return 0.10 +beverage->cost();
        }
        else if (beverage->getSize() ==GRANDE)
        {
               return 0.15 + beverage->cost();
        }
        else
        {
               return 0.20 +beverage->cost();
        }
}
 
// 装饰者具体类2
stringMocha::getDescription()
{
        return beverage->getDescription() +", Mocha";
}
 
double Mocha::cost()
{
        if (beverage->getSize() == TALL)
        {
               return 0.20 +beverage->cost();
        }
        else if (beverage->getSize() ==GRANDE)
        {
               return 0.25 +beverage->cost();
        }
        else
        {
               return 0.30 +beverage->cost();
        }
}
 
// 装饰者具体类3
stringSoy::getDescription()
{
        return beverage->getDescription() +", Soy";
}
 
double Soy::cost()
{
        if (beverage->getSize() == TALL)
        {
               return 0.15 +beverage->cost();
        }
        else if (beverage->getSize() ==GRANDE)
        {
               return 0.20 +beverage->cost();
        }
        else
        {
               return 0.25 +beverage->cost();
        }
}
 
// 装饰者具体类4
stringWhip::getDescription()
{
        return beverage->getDescription() +", Whip";
}
 
double Whip::cost()
{
        if (beverage->getSize() == TALL)
        {
               return 0.10 +beverage->cost();
        }
        else if (beverage->getSize() ==GRANDE)
        {
               return 0.15 +beverage->cost();
        }
        else
        {
               return 0.20 +beverage->cost();
        }
}

#include "DecoratorPattern.h"

void main()
{
	cout << "---------------------------------------------" << endl;
	Beverage* beverage = new Espresso();
	if (beverage->getSize() == TALL)
	{
		cout << "Little cup: " << endl;
	}
	else if (beverage->getSize() == GRANDE)
	{
		cout << "Middle cup: " << endl;
	}
	else
	{
		cout << "Big cup: " << endl;
	}
	cout << fixed << setprecision(2) << beverage->getDescription()
		 << " $" << beverage->cost() << endl;

	cout << "---------------------------------------------" << endl;
	Beverage* beverage2 = new DarkRoast();
	beverage2 = new Mocha(beverage2);
	beverage2 = new Mocha(beverage2);
	beverage2 = new Whip(beverage2);
	if (beverage2->getSize() == TALL)
	{
		cout << "Little cup: " << endl;
	}
	else if (beverage2->getSize() == GRANDE)
	{
		cout << "Middle cup: " << endl;
	}
	else
	{
		cout << "Big cup: " << endl;
	}
	cout << fixed << setprecision(2) << beverage2->getDescription()
		 << " $" << beverage2->cost() << endl;

	cout << "---------------------------------------------" << endl;
	Beverage* beverage3 = new HouseBlend();
	beverage3 = new Soy(beverage3);
	beverage3 = new Mocha(beverage3);
	beverage3 = new Whip(beverage3);
	if (beverage3->getSize() == TALL)
	{
		cout << "Little cup: " << endl;
	}
	else if (beverage3->getSize() == GRANDE)
	{
		cout << "Middle cup: " << endl;
	}
	else
	{
		cout << "Big cup: " << endl;
	}
	cout << fixed << setprecision(2) << beverage3->getDescription()
		 << " $" << beverage3->cost() << endl;

	cout << "---------------------------------------------" << endl;
	Beverage* beverage4 = new DarkRoast();
	beverage4->setSize(TALL);
	beverage4 = new Mocha(beverage4);
	beverage4->setSize(TALL);
	beverage4 = new Mocha(beverage4);
	beverage4->setSize(TALL);
	beverage4 = new Whip(beverage4);
	beverage4->setSize(TALL);
	if (beverage4->getSize() == TALL)
	{
		cout << "Little cup: " << endl;
	}
	else if (beverage4->getSize() == GRANDE)
	{
		cout << "Middle cup: " << endl;
	}
	else
	{
		cout << "Big cup: " << endl;
	}
	cout << fixed << setprecision(2) << beverage4->getDescription()
		<< " $" << beverage4->cost() << endl;

	cout << "---------------------------------------------" << endl;
	Beverage* beverage5 = new HouseBlend();
	beverage5->setSize(VENTI);
	beverage5 = new Soy(beverage5);
	beverage5->setSize(VENTI);
	beverage5 = new Mocha(beverage5);
	beverage5->setSize(VENTI);
	beverage5 = new Whip(beverage5);
	beverage5->setSize(VENTI);
	if (beverage5->getSize() == TALL)
	{
		cout << "Little cup: " << endl;
	}
	else if (beverage5->getSize() == GRANDE)
	{
		cout << "Middle cup: " << endl;
	}
	else
	{
		cout << "Big cup: " << endl;
	}
	cout << fixed << setprecision(2) << beverage5->getDescription()
		<< " $" << beverage5->cost() << endl;

	cout << "---------------------------------------------" << endl;
	delete beverage;
	delete beverage2;
	delete beverage3;
	delete beverage4;
	delete beverage5;
	beverage = NULL;
	beverage2 = NULL;
	beverage3 = NULL;
	beverage4 = NULL;
	beverage5 = NULL;
}


    该例的运行结果如图1所示,一定要注意C++中指针的内存释放问题!!!

 

设计模式系列(三)装饰者模式(Decorator Pattern)_第1张图片

图1 运行结果

 

    该例的UML类图如图2所示。

 

设计模式系列(三)装饰者模式(Decorator Pattern)_第2张图片

图2 UML类图

 

    该例主要是一个咖啡店的售卖系统,有最基本的咖啡抽象组件--Beverage,这个组件为被装饰者和装饰者提供了统一的接口。具体的组件是图2中左上角的四个组件,这四个组件是具体的咖啡类型,它们有不同的名称和价格,这四个组件就是被装饰者。大家都知道,每种咖啡可以加不同的配料,如牛奶、奶泡、豆浆、摩卡等,这些配料就是具体的装饰者,而它们的共同父类就是一个继承于Beverage抽象组件的一个抽象装饰者,它为装饰者提供统一的接口。正如喝咖啡可以随意组合配料一样,这里可以通过排列组合具体的装饰者实现不同的咖啡配料,即所谓的扩展功能,如牛奶豆浆咖啡或者豆浆摩卡咖啡,甚至于牛奶豆浆摩卡奶泡咖啡,具体是什么咖啡都可以根据顾客的选择进行动态变化。这里用到了组合和委托,组合在于四个装饰者中都包含一个指向被装饰者的指针,委托在于每一次计算价格的时候,装饰者委托这个指针动态地进行价格计算,这里也用到了多态的特性。

 

    最后需要注意的是,本例通过一个枚举类型(图2右上角)表示咖啡的不同大小的杯,在咖啡抽象组件--Beverage中也定义了set和get函数来设置和获取咖啡的大小杯,并且在测试函数中也用到了很多特性,大家可以慢慢理解一下,有问题的可以留言。

你可能感兴趣的:(设计模式,C++,Pattern,Decorator,装饰者模式,UML类图)