【设计模式】之装饰模式(Decorator)
原创
©著作权归作者所有:来自51CTO博客作者Lyndon_梁飞的原创作品,请联系作者获取转载授权,否则将追究法律责任
装饰模式的定义为 动态地为一个对象添加额外的功能,在扩展功能方面装饰模式比生成子类方式提供了一种更灵活的方法。
英文定义为: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之后添加自己的功能,就像代码例子中的星巴克咖啡计算价格一样。
装饰模式的结构图如下:
因为具有动态添加功能的特性,所以与策略模式(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());
}
}
结论:星巴克咖啡怎么那么便宜,唉,苦逼啊。。。