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

文章讨论了如何使用装饰者模式解决咖啡订单系统中添加调料导致的类爆炸问题。对比了通过继承和装饰者模式实现扩展的不同,强调装饰者模式在运行时提供更灵活的对象行为扩展,同时遵循开闭原则,减少代码修改带来的风险。示例展示了如何创建Beverage、Espresso、Mocha等类,并通过装饰者动态添加调料成本。
摘要由CSDN通过智能技术生成

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

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

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

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

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

 可以通过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可以看到装饰者模式的一个“缺点”,设计中有大量的小类存在。

总结:

  • 装饰者和被装饰对象要具有相同的超类型(在任何需要原始对象(被包装的)的场合,可以用装饰过的对象替代)
  • 装饰者中存储一个被装饰者
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值