装饰者模式:动态地将责任附加到对象上,若到扩展功能,装饰者提供了比继承更有弹性的替代方案。
UML图
有这样一个需求,咖啡店出售各式咖啡,如深焙、低卡、摩卡等,也有各种调料,如牛奶、奶泡等。
咖啡店需要根据咖啡中所放入的不同调料收取不同的费用。用装饰者模式来实现
定义一个抽象组件
package com.headfirst.chapter3;
/**
* 定义了一个抽象类,用于表示组件,它定义了一个抽象方法cost
*/
public abstract class Beverage {
String description;
public String getDescription() {
return description;
}
public abstract double cost();//计费方法
}
下面两个是具体组件,也就是被装饰者
1,深焙咖啡
package com.headfirst.chapter3;
public class DarkRoast extends Beverage {//深焙咖啡
public DarkRoast() {
this.description = "DarkRoast";
}
public double cost() {
return 0.89;
}
}
2,混合咖啡
package com.headfirst.chapter3;
public class HouseBlend extends Beverage {
public HouseBlend() {
this.description = "HouseBlend";
}
public double cost() {
return 1.89;
}
}
装饰者
这里定义了一个抽象方法getDescription,那么子类必须它来增加描述
如Houseblend Milk
package com.headfirst.chapter3;
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
下面两个是装饰者
package com.headfirst.chapter3;
public class Milk extends CondimentDecorator {
private Beverage beverage;//这个引用指向被装饰者
public Milk(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + " Milk";
}
public double cost() {
return beverage.cost() + 0.20;
}
}
package com.headfirst.chapter3;
public class Mocha extends Beverage {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + " Mocha";
}
public double cost() {
return beverage.cost()+0.59;
}
}
测试类:
package com.headfirst.chapter3;
public class Test {
public static void main(String[] args) {
Beverage darkRoast = new DarkRoast();
darkRoast = new Mocha(darkRoast);
darkRoast = new Milk(darkRoast);
System.out.println(darkRoast.getDescription()+" $"+darkRoast.cost());
}
}
最后打印出:DarkRoast Mocha Milk $1.68
设计原则:类应该向修改关闭,向扩展开放
类的继承是扩展开幕式之一,但不见得是达到弹性设计的最佳方式。如果依赖继承,那么类的行为只能在编译时静态决定。
反之,利用组合,可以把装饰者混合着用,而且是在运行时。