定义
动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。
理解
使用对象组合的方式,做到运行时装饰类。这样可以在不修改任何底层代码的情况下,给你的(或别人的)对象赋予新的职责。动态的将责任附加到对象上,想要扩展功能,装饰者提供有别于继承的另一种选择。我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。这样的设计具有弹性,可以应对改变,可以接收新的功能来应对改变。
设计初衷
通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。
装饰者类类在构造中引入一个被装饰组件,拿到它之后可以在组件的行为(方法)的前后加上自己的行为,甚至可以将组件的行为覆盖掉,达到动态扩展新行为的功能。
UML类图
应用实例
这里引用了《Head First 设计模式》中关于装饰者模式的例子
一份咖啡可能加摩卡、奶泡等辅料。而每一个辅料的价格不一样,如何设计程序才能让最终计算咖啡价格更简单。使用装饰者模式再好不过。
/**
* 该类为饮料抽象类,定义抽象方法cost(),用于计算饮料价格
* 抽象组件
* @author xiangge.zeng
*/
public abstract class Beverage {
String description = "UnKnown Beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
/**
* 浓缩咖啡,是一种饮料,继承Beverage基类
* 具体组件
* @author xiangge.zeng
*
*/
public class Espresso extends Beverage{
/**
* 为了设置该饮料的描述,编写该构造器
* description实例变量继承于父类
*/
public Espresso(){
description = "Espresso";
}
/**
* 计算价钱方法,返回浓缩咖啡的价格
*/
public double cost() {
return 1.99;
}
}
/**
* 调料类,继承于饮料基类。是抽象装饰者,用于装饰饮料组件
* @author xiangge.zeng
*
*/
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
/**
* 装饰者摩卡,用于装饰咖啡.装饰者扩展于组件,为了和组件保持统一从而装饰组件
* @author xiangge.zeng
*
*/
public class Mocha extends CondimentDecorator{
/**
* 让装饰者在构造中引入一个组件,从而拿到它、装饰它
* 做法如下: 1、加入组件实例变量
* 2、组件作为构造参数传入构造器
*/
private 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 CoffeShop {
public static void main(String[] args) throws Exception{
//点一杯浓缩咖啡
Beverage b = new Espresso();
//打印价格与描述
System.out.println(b.getDescription()+" :"+b.cost());
//点一杯加两分摩卡和一份WHip的Espresso
Beverage b1 = new Espresso ();
//b1被两份Mocha和一份Whip所装饰
b1 = new Mocha(b1);
b1 = new Mocha(b1);
b1 = new Whip(b1);
//或可以直接写成如下形式:
b1 = new Mocha(new Mocha(new Whip(b1)));
//打印价格与描述
System.out.println(b1.getDescription()+" :"+b1.cost());
}
}
调用过程

Java中的装饰者模式:Java IO
FileInputStream是低级流,它从文件中读取数据,但是它的性能有时不尽如人意。我们可以用一些高级流装饰它。所谓的套用;它是“被装饰者”。BufferedInputStream是一个具体的装饰者,它在原来的基础上实现了利用缓冲来改进性能。
BufferedInputStream,LineNumberInputStream都扩展自FilterInputStream,它是一个抽象的装饰类。