一杯咖啡,带你彻底搞懂装饰者模式!
导语:你是否曾经为代码的臃肿不堪而烦恼?你是否曾经为功能的扩展而绞尽脑汁?今天,我们就从一个简单的咖啡店点单系统开始,带你领略装饰者模式的魅力,让你的代码从此优雅而灵活!
一、从一个咖啡店的故事开始
想象一下,你经营着一家咖啡店,店里提供各种咖啡,比如浓缩咖啡(Espresso)、美式咖啡(HouseBlend)等等。顾客可以根据自己的喜好,添加各种调料,比如牛奶(Milk)、摩卡(Mocha)等等。
问题来了:如何设计一个系统,能够方便地计算不同咖啡和调料组合的价格呢?
最直观的想法:为每一种咖啡和调料的组合创建一个类,比如 EspressoWithMilk、HouseBlendWithMochaAndMilk 等等。但是,这种设计方式存在明显的缺陷:
- 类爆炸:随着咖啡和调料种类的增加,类的数量会呈指数级增长,最终导致代码臃肿不堪。
- 难以维护:如果需要修改某种咖啡或调料的价格,就需要修改所有相关的类,维护成本极高。
- 难以扩展:如果需要添加新的咖啡或调料,就需要创建大量的新类,扩展性极差。
二、装饰者模式登场
装饰者模式(Decorator Pattern)就是为了解决上述问题而生的。它允许我们动态地给一个对象添加一些额外的职责,而不会影响其他对象。
让我们用装饰者模式来重新设计咖啡店的点单系统:
- 定义抽象组件(Component):
Beverage
类,表示所有咖啡的基类,包含描述和价格两个属性。 - 定义具体组件(ConcreteComponent):
Espresso
、HouseBlend
等类,继承自Beverage
,表示具体的咖啡种类。 - 定义抽象装饰者(Decorator):
CondimentDecorator
类,继承自Beverage
,并持有一个Beverage
对象的引用。 - 定义具体装饰者(ConcreteDecorator):
Milk
、Mocha
等类,继承自CondimentDecorator
,表示具体的调料。
代码示例:
// 抽象组件
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
// 具体组件
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
// 抽象装饰者
public abstract class CondimentDecorator extends Beverage {
Beverage beverage;
public CondimentDecorator(Beverage beverage) {
this.beverage = beverage;
}
public abstract String getDescription();
}
// 具体装饰者
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
super(beverage);
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost();
}
}
使用装饰者模式:
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
beverage = new Mocha(beverage);
System.out.println(beverage.getDescription() + " $" + beverage.cost());
输出结果:
Espresso $1.99
Espresso, Mocha $2.19
三、装饰者模式的优势
- 灵活扩展:可以动态地添加或移除功能,而无需修改原有代码。
- 避免类爆炸:无需为每个功能组合创建子类,代码更加简洁。
- 符合开闭原则:对扩展开放,对修改关闭,提高了代码的可维护性和可扩展性。
四、装饰者模式的应用场景
装饰者模式在实际开发中有着广泛的应用,例如:
- Java I/O 流:
BufferedInputStream
、DataInputStream
等都是装饰者模式的典型应用。
- 日志记录:可以为日志记录器添加不同的功能,比如日志级别过滤、日志格式化等。
- 权限控制:可以为用户添加不同的权限,比如管理员权限、普通用户权限等。
五、总结
装饰者模式是一种非常实用的设计模式,它可以帮助我们编写出更加灵活、可扩展、易维护的代码。希望通过这篇文章,你能对装饰者模式有一个更深入的理解,并能在实际开发中灵活运用它。
最后,留一个思考题: 除了咖啡店的例子,你还能想到哪些场景可以使用装饰者模式?欢迎在评论区留言分享你的想法!
关注公众号,获取更多精彩内容!
(本文参考《Head First 设计模式》第3章)