欢迎来到 Starbuzz Coffee
星巴克作为一家扩展最快的咖啡店,它们现在需要更新饮料订购系统以便满足现在庞大的需求。这个订购系统的第一版如下:
显然这对于日后的维护来说,完全是个噩梦。这里需要提到一个设计原则(Open-Closed Principles):
类应当对扩展开放,对修改封闭
Classes should be open for extension, but closed for modication.
我们的目标是让类易于扩展以便包含新的行为,同时不去修改现存的源代码。但是并不是在每个部分都要采用这一原则,如果到处滥用,反而会导致代码复杂。一般在代码最重要并且会变化的地方采用这一原则。
使用 Decorator Pattern
如果一个顾客需要 Dark Roast,加 Mocha 和 Whip。我们这么做:
- Take a DarkRoast object
- Decorate it with a Mocha object
- Decorate it with a Whip object
- Call the cost() method and rely on delegation to add on the condiment costs
但是这里的 decorate 怎么做?我们可以把它看做封装器(wrapper)。
下面给一个正式的定义:
The Decorator Pattern attaches additional reponsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
下面给一个图像实例:
而在之前的情境下,可以画出如下框架:
public abstract class Beverage
{
String description = "Unknown Beverage";
public String getDescription()
{
return description;
}
public abstract double cost();
}
// 与此类似实现咖啡类 HouseBlend,Espresso,Decaf 类
public class DarkRoast extends Beverage
{
public DarkRoast()
{
description = "Dark Roast Coffee";
}
public double cost()
{
return 0.99;
}
}
public abstract class CondimentDecorator extends Beverage
{
public abstract String getDescription();
}
// 与此类似实现调料类 SteamMilk,Soy,Whip 类
public class Mocha extends CondimentDecorator
{
Beverage beverage;
public Mocha(Beverage beverage)
{
this.beverage = beverage;
}
public String getDescription()
{
return beverage.getDescription() + ", Mocha";
}
public double cost()
{
return .20 + beverage.cost();
}
}
// 测试
public class StarbuzzCoffee
{
public static void main(String[] args)
{
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
Beverage beverage2 = new DarkRoast();
beverage2 = new Mocha(beverage2);
beverage2 = new Mocha(beverage2);
beverage2 = new Whip(beverage2);
System.out.println(beverage2.getDescription() + " $" + beverage2.cost());
Beverage beverage3 = new HouseBlend();
beverage3 = new Soy(beverage3);
beverage3 = new Mocha(beverage3);
beverage3 = new Whip(beverage3);
System.out.println(beverage3.getDescription() + " $" + beverage3.cost());
}
}
现实中的 Decorators:Java I/O,Java I/O 大量使用了 Decorator Pattern。但是 Java I/O 也指出了 Decorator Pattern的一个问题:使用这个模式会有很多小类,这会让使用者感到恐慌。