装饰者模式定义:
装饰者模式动态的将责任附加到对象上,若要扩展对象,装饰者模式提供了比继承更有弹性的替代方案。
装饰者模式类图:

说明:
a) ConcreteComponent是我们要动态地加上新行为的对象,它扩展自Component;
b) 每个组件都可以单独使用,或者被装饰者包装起来使用;
c) 每个装饰者都“有一个”(包装一个)组件,也就是说,装饰者有一个实例变量以保存某个Component的引用;
d) Decorator是装饰者共同实现的接口(也可以是抽象类);
e) ConcreteDecorator有一个实例变量,可以记录所装饰的事物(装饰者包装的Component);
f) 装饰者可以加上新的方法,新行为是通过在旧行为前面或后面做一些计算来添加的。
装饰者模式具体示例:
在购买咖啡时,可以在咖啡中加入各种调料,例如:蒸奶(Steamed Milk)、豆浆(Soy)、摩卡(Mocha)或覆盖奶泡。
咖啡店会根据所加入的调料收取不同的费用,所以咖啡店订单系统必须考虑到这些调料部分。
现在考虑用装饰者模式来完成这个订单系统,以实现饮料结算和描述接口。下图是采用装饰者模式的咖啡订单系统类图:

说明:
HouseBlend、DarkRoast、Espresso和Decaf是四个具体的组件,每一个组件代表一种咖啡类型;
Milk、Mocha、Soy和Whip同样继承自Beverage,是调料装饰者,它们除了必须实现cost()之外,还必须实现getDescription()。
实现代码:
饮料基类:
/**
* 饮料基类
*/
public abstract class Beverage {
String description = "Unkown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
调料抽象类CondimentDecorator:
/**
* 调料基类
*/
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
具体的饮料:
public class DarkRoast extends Beverage {
public DarkRoast(){
description = "Dark Roast Coffee";
}
@Override
public double cost() {
return 0.67;
}
}
public class HouseBlend extends Beverage {
public HouseBlend(){
description = "House Blend Coffee";
}
@Override
public double cost() {
return 0.89;
}
}
具体的调料类:
/**
* Mocha是一个装饰者,所以它扩展自CondimentDecorator;
* CondimentDecorator继承自Beverage;
*
* 要让Mocha能够引用Beverage,做法如下:
* 1. 用一个实例变量记录饮料,也就是被装饰者;
* 2. 想办法让被装饰者(饮料)被记录到实例变量中。
*
* 这里的做法是:把饮料当做构造器的参数,再由构造器将此饮料记录在实例变量中。
*/
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
@Override
public double cost() {
return 0.20 + beverage.cost();
}
}
public class Soy extends CondimentDecorator {
Beverage beverage;
public Soy(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Soy";
}
@Override
public double cost() {
return 0.13 + beverage.cost();
}
}
public class Whip extends CondimentDecorator {
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
@Override
public double cost() {
return 0.13 + beverage.cost();
}
}
测试代码:
public class Coffee {
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());
}
}
Java I/0类库是使用装饰者模式最典型的例子,请看下面的类图:

但是Java I/0也引出了装饰者模式的一个“缺点”:利用装饰者模式,常常造成设计中有大量的小类,数量实在太多,
可能会造成使用此API程序员的困扰。现在已经了解了装饰者模式的工作原理,以后当使用别人的大量装饰的API时,
就可以很容易的辨别出他们的装饰者类是如何组织的,以方便用包装方式取得想要的行为。
来源:https://www.cnblogs.com/dasenlin/archive/2012/12/23/2830255.html