设计模式之三:装饰者模式

装饰者模式可以在不修改任何底层代码的情况下,给对象赋予新的职责(使用对象组合的方式,在运行时装饰类)。

假定星巴兹咖啡需要更新订单系统,而他们原先类的设计如图:

 现在他们考虑客户可以选择添加调料(蒸奶,豆浆,摩卡等)到这几种咖啡中。

实现一:每种调料和咖啡的组合都形成一个新类,然后覆盖cost方法。这样会造成“类爆炸”,使得维护起来特别困难(假设需要新增加一种口味,那么类成几何倍数增长。如果要改变一种调味的价格,也需要修改许多的类)

 实现二:利用实例变量和继承来追踪这些调料。

设计模式之三:装饰者模式_第1张图片

 可以通过set方法来设置添加调料的种类,然后在基类的cost计算调料的价格。子类中的cost再调用父类的cost并加上自己的价格。

实现二的设计存在以下的一些问题:

  • 一旦出现新的调料,我们就需要添加新的方法,并改变超类中的cost方法。
  • 对以后开发出的新饮料而言,某些调料可能并不适合,但子类仍将继承这些方法。
  • 顾客想要双倍摩卡咖啡。

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

设计原则:类应该对扩展开放,对修改关闭

对修改关闭是因为,现有代码是正确的,如果允许修改,则容易引入bug。

实现三:装饰者模式

  1. 拿一个DarkRoast对象
  2. 以摩卡对象装饰它
  3. 以奶泡对象装饰它
  4. 调用cost方法,并依赖委托将调料价格加上

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

  • 装饰者和被装饰对象有相同的超类型
  • 可以用一个或多个装饰着包装一个对象
  • 装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象替代
  • 装饰者可以在被装饰者行为之前/之后,加上自己的行为
  • 对象可以在任何时候被装饰,可以运行时动态地,不限量地用装饰者装饰

(利用继承来达到“类型匹配”,而不是利用继承获得“行为”)

class Beverage
{
private:
	String description = "Unknown Beverage";

public:
	virtual String getDescription()
	{
		return description;
	}

	virtual double cost() = 0;
};

class Espresson : public Beverage
{
public:
	Espresson()
	{
		description = "Espresson";
	}

	double cost()
	{
		return 1.99;
	}
};
class Mocha : public Beverage
{
private:
	Beverage* beverage;

public:
	Mocha(Beverage* beverage)
	{
		this->beverage = beverage;
	}

	String getDescription()
	{
		return beverage->description() + ".Mocha";
	}

	double cost()
	{
		.20 + beverage->cost();
	}
};
// 测试代码

int main()
{
	// 不知道这样内存都删干净了没有,或者用智能指针更好
	Beverage* beverage = new Espresson();
	Beverage* beverage1 = new Mocha(beverage);
	Beverage* beverage2 = new Whip(beverage1);

	delete beverage;
    delete beverage1;
    delete beverage2;
}

真实世界的装饰者:

LineNumberInputStream->BufferedInputStream->FileInputStream

 从Java.io可以看到装饰者模式的一个“缺点”,设计中有大量的小类存在。

你可能感兴趣的:(设计模式,设计模式)