《Head First 设计模式》读书笔记之装饰者模式

本文探讨了在咖啡店场景下使用装饰者模式来设计饮料类的方法,解决了传统继承方式带来的类膨胀问题,同时遵循开放-关闭原则,使得添加新功能更为灵活。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.背景

现在有以下场景:咖啡店中有各种咖啡,而且各种咖啡可以加入不同的调料,比如蒸奶、豆浆、摩卡等,然后根据加入的调料收取相应的费用。现在要针对这样的使用要求设计出咖啡店中的各种饮料对象。

2.过程分析

书中提到了一种现有的设计方案,其类图如下:

1

其中Beverage为饮料的基类,店中所有的咖啡都继承自Beverage,并实现cost方法计算这种咖啡的费用,如现在有一种加了摩卡和奶泡的深焙咖啡,就需要建立个DarkRoastWithMochaAndWhip类,const方法中返回这种咖啡的价格。如果按照这种方法设计,那么店中有多少种咖啡的搭配方法,那么就有多少个咖啡类,显然是不能适用的。那么,针对这样的缺陷,又有一种设计方案:

2

所有的咖啡都继承Beverage基类,得到不同的description的属性,基类中已经保持有各种调料的状态,cost方法根据这些调料的有无来计算出价格,这样就可以大大减少类的数量,有几类咖啡就有几个类。如果需要加入一种调料,就调用相应的set方法,然后cost就能动态地计算出价格。看上去很符合要求。但是这样的设计却违反了一个重要的设计原则:开放-关闭原则。如果要增加一种新的调料,或者修改一种调料的价格,则要对Beverage进行相应的修改,而且对于调料的添加也不够灵活,比如添加两份牛奶,这样的设计就无法达到这样的要求。

3.定义

根据以上的分析,发现两种不同的方案有着各自的缺陷,先引出装饰者模式定义:装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

4.装饰者模式类图

3

其中HouseBlend和DarkRoast是咖啡类型,需要被装饰,充当ConcreteComponentde的角色。Milk和Mocha是装饰者,用来装饰咖啡。所有的装饰者都要继承自CondimentDecorator,以表示他们是一个装饰者。而所有的装饰者和被装饰者都有一个共同的超类:Beverage(在装饰者模式中统称为Component),用来表示装饰者和被装饰者是同一类型,这样就可以在装饰者中通过引用Beverage来装饰所有的ConcreteComponentde,这样可以在被装饰者外面包含一层装饰者,外面又可以包含一层装饰者,这样一层层包含,达到动态修饰的目的。不同的装饰中会对他们的相关方法返回结果进行装饰,从而达到为该方法添加附加功能的能力。例如在Milk中调用beverage的cost方法,并在其返回值的基础之上+0.1,做为Milk自己的cost方法的返回值,这样,被Milk装饰后,调用cost方法后其值就会增加0.1。

5.设计原则

开放-关闭原则:对扩展开放,对修改关闭。就是说在设计的时候,要尽可能做到在以后的功能扩展中不去修改原有的代码,只是往系统中添加新的组件来完成需要的功能。

6.源代码

Beverage

public abstract class  Beverage {
	protected String description = "unknown";
	
	public String getDescription(){
		return description;
	}
	
	public abstract double cost();
}
CondimentDecorator

public abstract class CondimentDecorator extends Beverage{
	public abstract String getDescription();
	
}

HouseBlend

public abstract class  Beverage {
	protected String description = "unknown";
	
	public String getDescription(){
		return description;
	}
	
	public abstract double cost();
}


Mocha

public class Mocha extends CondimentDecorator {
	Beverage beverage;
	
	public Mocha(Beverage beverage){
		this.beverage = beverage;
	}
	
	@Override
	public String getDescription() {
		return beverage.getDescription() + ",Mocha";
	}

	@Override
	public double cost() {
		
		return 0.5 + beverage.cost();
	}

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值