装饰模式的定义为 动态地为一个对象添加额外的功能,在扩展功能方面装饰模式比生成子类方式提供了一种更灵活的方法。

英文定义为:Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.


装饰模式可以有效地避免太多继承而导致类爆炸的现象。

在open-close的原则下,装饰对于客户端因应该是透明的,只有这样才能保证可以动态地添加功能,否则每添加一次功能就需要修改一下客户端的调用方式。

decorator与component既是继承关系又是引用关系(has-a),decorator与Concrete Component都是继承自Component,这样的话只要客户端使用Component对象,即实现了多态的功能与隐藏装饰的功能。

在decotrator内部会有一个component的引用,decorator首先拦截送给component的消息,在真正调用component的消息处理之前and/or之后添加自己的功能,就像代码例子中的星巴克咖啡计算价格一样。

装饰模式的结构图如下:

【设计模式】之装饰模式(Decorator)_blend

因为具有动态添加功能的特性,所以与策略模式(Strategy)有相似之处,但是两者的delegation关系其实是正好相反的,decorator对于使用它的对象是透明,也就说被装饰的对象其实是不知道它被装饰了;而使用strategy的对象是明确地知道它使用的是什么strategy。decorator改变的是对象的"skin",而strategy改变的是对象的"gut"。


《Header First Design Patterns》中的给出的星巴克咖啡的例子如下,首先定义一个咖啡跟配料的基类Beverage,咖啡类的角色是concrete Component,配料就是Decorator,原因很明显,咖啡可以添加不同的配料,因此配料就可以装饰咖啡。


public abstract class Beverage {
String description = "Unknown Beverage";

public String getDescription() {
return description;
}

public abstract double cost();
}


以此定义三种具体的咖啡类,DarkRoast、Espresso、HouseBlend


public class DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}

public double cost() {
return .99;
}
}
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}

public double cost() {
return 1.99;
}
}
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}

public double cost() {
return .89;
}
}

然后定义decorator的接口。


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

具体的decorator。


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 Soy extends CondimentDecorator {
Beverage beverage;

public Soy(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription() + ", Soy";
}

public double cost() {
return .15 + beverage.cost();
}
}
public class Whip extends CondimentDecorator {
Beverage beverage;

public Whip(Beverage beverage) {
this.beverage = beverage;
}

public String getDescription() {
return beverage.getDescription() + ", Whip";
}

public double cost() {
return .10 + 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());
}
}

结论:星巴克咖啡怎么那么便宜,唉,苦逼啊。。。