定义
装饰者模式:动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)
案例
星巴克咖啡订单项目(咖啡馆):
- 咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
- 调料:Milk、Soy(豆浆)、Chocolate
- 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
- 使用OO的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖啡加调料组合。
//Drink,饮品抽象类,提取饮品的共同特点
public abstract class Drink {
private String desr;
private float price = 0.0f;
public String getDesr() {
return desr;
}
public void setDesr(String desr) {
this.desr = desr;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public abstract float cost(); //抽象的计算总价的方法
}
//咖啡抽象类,继承饮品类,是饮品的一个分支
public abstract class Coffee extends Drink {
@Override
public float cost() {
return super.getPrice();
}
}
//咖啡实现类(具体的咖啡)
//黑咖啡
public class ShortBlack extends Coffee{
public ShortBlack() {
setDesr("黑咖啡");
setPrice(4.0f);
}
}
//美式咖啡
public class American extends Coffee{
public American() {
setDesr("美式咖啡");
setPrice(8.0f);
}
}
//装饰类,本例中的是调料
//注意继承Drink类
public abstract class Decorator extends Drink {
private Drink drink; //组合一个单品饮料
public Decorator(Drink drink) {
this.drink = drink;
}
@Override //重写计算总价的方法,加上调料的价钱
public float cost() {
return super.getPrice()+drink.cost();
}
@Override //重写饮品描述的方法
public String getDesr() {
return super.getDesr()+" "+super.getPrice()+" && "+drink.getDesr();
}
}
//具体调料
//巧克力调料
public class Chocolate extends Decorator {
public Chocolate(Drink drink) {
super(drink);
setDesr("巧克力");
setPrice(1.5f);
}
}
//牛奶调料
public class Milk extends Decorator {
public Milk(Drink drink) {
super(drink);
setDesr("牛奶");
setPrice(1.0f);
}
}
//客户类,测试
public class Client {
public static void main(String[] args) {
//Drink drink = new ShortBlack();
Drink drink = new American();
System.out.print(drink.getDesr());
System.out.println(" 总价"+drink.cost());
drink = new Milk(drink); //单品美式+牛奶
drink = new Chocolate(drink); //单品美式+牛奶+巧克力
System.out.print(drink.getDesr());
System.out.println(" 总价"+drink.cost());
System.out.println(((Decorator)drink).getDrink().getDesr());
drink = new Chocolate(drink); ////单品美式+牛奶+巧克力+巧克力
System.out.print(drink.getDesr());
System.out.println(" 总价"+drink.cost());
System.out.println(
((Decorator)(((Decorator)drink).getDrink())).getDrink().getPrice()
);
}
}
装饰者模式解决星巴克咖啡订单
装饰者模式下的订单:2份巧克力+一份牛奶的LongBlack
说明
- Milk包含了LongBlack
- 一份Chocolate包含了(Milk+LongBlack)
- 一份Chocolate包含了(Chocolate+Milk+LongBlack)
这样不管是什么形式的单品咖啡+调料组合,通过递归方式可以方便的组合和维护
个人总结
此模式适合某对象添加新功能(或者属性)后,顶层都为同一类的对象