一、定义
动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
二、理解
如下图所示,在对象内部创建一个实例变量,用来记录被装起来的实例,然后实现一层一层装饰起来。当需要执行贯穿所有实例的方法是,通过逐级调用内层被装饰实例实现调用:
三、实现
public abstract class Beverage { //饮料,抽象类 String description = "Unknown Beverage"; public String getDescription(){ return description; } public abstract double cost(); //神奇的抽象方法 } public class DarkRoast extends Beverage{ //深培咖啡 public DarkRoast(){ description = "DarkRoast Coffee"; } public double cost(){ return 0.99; } } public class Decat extends Beverage { //低咖啡因咖啡 public Decat(){ description = "Decat Coffee"; } public double cost(){ return 1.05; } } 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 0.89; } } public abstract class CondimentDecorator extends Beverage{ //抽象类继承抽象类 public abstract String getDescription(); //抽象类方法 } 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 0.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 0.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 0.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); //只要有引用,就不会被GC回收 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()); } }
四、总结
1、装饰者与被装饰者必须是一样的类型,也就是有共同的超类。上面的demo使用继承实现类型匹配。
2、装饰者与组件组合时,得到的新行为,来源于组合对象。
3、通常装饰类的实现采用的是抽象类,而非接口。