牛骨文教育服务平台(让学习变的简单)

装饰者模式

模式定义:

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

      装饰者和被装饰者有相同的超累类型。

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

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

      装饰者可以委托被装饰者的行为之前与或之后,加上自己的行为,以达到特定的目的。

      对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。

模式结构:

举例:

      购买咖啡时,可以在其中加入各种调料,例如:蒸奶(Steamed Milk),豆浆(Soy),摩卡(Mocha)或覆盖奶泡。咖啡馆会根据所加入的调料收取不同的费用。

      解决方法:我们以饮料为主体,然后在运行时以调料来装饰饮料。比方说顾客想要摩卡和奶泡深焙咖啡,那么,要做的是:拿一个深焙咖啡(DarkRoast)对象,以摩卡(Mocha)对象装饰它,以奶泡对象装饰它,调用cost()方法,并依赖委托将调料的价钱加上去。

UML设计:

编程实现及执行结果:

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

class Beverage
{
public:
	Beverage(string str = "Unknow Beverage")
		:description(str){}

	virtual string getDescription()
	{
		return description;
	}

	virtual double cost(){return 0;}

private:
	string description;
};

class CondimentDecorator : public Beverage
{
public:
	string getDescription(){return "";}
};

class Espresso : public Beverage
{
public:

	Espresso():Beverage("Espresso"){}

	double cost()
	{
		return 1.99;
	}
};

class HouseBlend : public Beverage
{
public:
	HouseBlend():Beverage("HouseBlend Coffee"){}

	double cost()
	{
		return 0.89;
	}
};

class Mocha : public CondimentDecorator
{
public:
	Mocha(Beverage* beve)
	{
		beverage = beve;
	}
	
	string getDescription()
	{
		return beverage->getDescription()+", Mocha";
	}

	double cost()
	{
		return 0.20 + beverage->cost();
	}
private:
	Beverage* beverage;
};

class Whip : public CondimentDecorator
{
public:
	Whip(Beverage* beve)
	{
		beverage = beve;
	}
	
	string getDescription()
	{
		return beverage->getDescription()+", Whip";
	}

	double cost()
	{
		return 0.15 + beverage->cost();
	}
private:
	Beverage* beverage;
};
int main()
{
	Beverage* pBeverage = new Espresso();
	cout << pBeverage->getDescription() << " $" << pBeverage->cost() <<endl;

	Beverage* pBeverage2 = new Espresso();
	pBeverage2 = new Mocha(pBeverage2);
	pBeverage2 = new Mocha(pBeverage2);
	cout << pBeverage2->getDescription() << " $" << pBeverage2->cost() <<endl;

	pBeverage2 = new Whip(pBeverage2);
	cout << pBeverage2->getDescription() << " $" << pBeverage2->cost() <<endl;
	
	return 0;
}

执行结果:

Espresso$1.99

Espresso,Mocha, Mocha $2.39

Espresso,Mocha, Mocha, Whip $2.54

请按任意键继续. . .

      这样就可以是不同饮料加入不同的配料,而不用改动源代码,并且可以加入新的配料类型和饮料类型。

设计原则的应用:

      设计原则5:类应该对外扩展,对修改关闭。如装饰者模式中,我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。

       参考:Head First设计模式