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