这篇博客简要通过一个订单系统案例,各种调料装饰饮品,最后计算咖啡价格。由此介绍了对扩展开放-对修改关闭的设计原则和装饰者模式的基本概念,它的基础类图,最后用设计者模式将调味料作为装饰者,将饮料作为被装饰者。解决了这一问题并且实现了对应代码。
叮叮叮,我们万能的小明又接到任务了。这次甲方爸爸的要求是一个咖啡厅的订单系统。咖啡店中,顾客可以加入各种调料,例如,蒸奶(Steam Milk),豆浆(Soy),摩卡(Mocha)或者奶泡。咖啡厅会根据加入的调料收取不同的费用。所以订单系统必须要考虑调料价格。
还是那句话,作为一名优秀的程序员,小明很快想出来了解决方法。他将各种调料设计为实例bool类型变量,表示它们是否加上了对应的调料。这是他的基类Beverage(饮料的意思)图。
![]() |
![]() |
但是,很快小明发现,写代码很容易,维护这些代码却异常地困难。参考博客
此刻,小明面临了最重要的设计原则开放-关闭原则
类应该对扩展开放,对修改关闭
什么意思呢?就是说我们的设计应该使得类容易扩展,在不修改现有代码的情况下,就可以搭配新的行为。两个例子
这里小明想到了一个好办法,就是像套娃一样,用一层层的调料去装饰饮料。例如顾客想要一倍加了摩卡和奶泡的烘焙咖啡。要做的就是
![]() |
这就是一个装饰者模式的实例。
装饰者模式动态地将责任添加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
我们可以从这个实例中发现装饰者模式的特点
下面是装饰者模式的类图
![]() |
然而,装饰者模式同样是有它的阴暗面的,这像套娃一样一层套一层的会增加代码的复杂度,滋生很多的小类。尤其是在嵌套的装饰者多了之后,理解和调试代码都是一件麻烦事。而且当被装饰者依赖某种类型时,引入装饰者就可能出现状况。
知道了装配这模式的框架,那么让我们用咖啡订单系统套一套。
![]() |
后面都是代码,不感兴趣的朋友可以直接跳到小结。
让我们来实现Beverage类
public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
Condiment调料类
public abstract class CondimentDecorator extends Beverage {
Beverage beverage;
public abstract String getDescription();
}
饮料Espresso代码,其他饮料HouseBlend, DarkRoast, Espresso, Decaf都类似,这里就不照抄了
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
public double cost() {
return 1.99;
}
}
调料Mocha代码,其他的调料Milk, Soy, Whip等都类似,这里就不抄写了。
public class Mocha extends CondimentDecorator {
public Mocha(Beverage beverage) {
this.beverage = beverage;
// 装饰者的构造函数需要被装饰者被赋值
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost();
}
}
让我们写一个测试代码测试一下,这里的代码有些类没有实现。需要实现了才能运行
package headfirst.designpatterns.decorator.starbuzz;
public class StarbuzzCoffee {
public static void main(String args[]) {
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription()
+ " $" + beverage.cost());
//制造一个DarkRoast对象,并且装饰上两个摩卡,一个奶泡
//这样最后就能够返回一杯加上了两份摩卡和一个奶泡的烘焙咖啡的价格
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription()
+ " $" + beverage2.cost());
//返回一份加了Whip,Mocha,Soy的HouseBlend的价格
Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription()
+ " $" + beverage3.cost());
}
}
假如读者不想写代码,这里有代码的链接。
咖啡厅代码链接
在这篇博客中,我们又get到了新的设计原则:
扩展开放-对修改关闭
装饰者模式被我们加入了工具箱
装饰者模式动态地将责任添加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案
装饰者模式具有以下特点
Java.io包中的典型的装饰者模式如下。
![]() |
谢谢你的阅读。你们的阅读点赞是我更新最大的动力 (๑◕ܫ←๑)