装饰者模式:动态的将新功能(装饰者,如调料)附加到对象(主体,如单品咖啡)上。在对象功能扩展方面,它比继承更有弹性。
1、以咖啡馆订单系统项目为例
咖啡种类:Espresso、ShortBlack、LongBlack、Decaf
调料:Milk、Soy、Chocolate
咖啡可以点单品,也可以和任意调料混合,最后返回咖啡价格
一个差的方案,为每一个单品和单品与调料组合,创建类,如Espresso类、ShortBlack类、Espresso&Milk类、Espresso&Milk&Soy类等,每个类里返回咖啡价格,这种方案导致类爆炸
稍微好点但是也不好的方案是,设计一个抽象超类,把调料内置到超类中,可设置添加调料方法,在单品继承自超类的实现类里,通过判断是否设置有某种调料,再计算价钱,这种设计太繁琐,而且不易扩展,如要新增一种调料,那就要改动代码,容易出错
2、装饰者模式设计:
装饰者设计模式是通过递归方式调用对象方法的,装饰者要继承自抽象主体,并且会调用抽象主体的方法,装饰者是依附于主体的
形如new Chocolate(new Chocolate(new Milk(new LongBlack))),如果返回价格调用cost方法,由于装饰者(调料)也继承自主体(Drink),而且调料.cost方法中会调用drink中的cost,一直递归调用到单品的cost方法
3、装饰者模式代码示例
//主体类 public abstract class Drink { private String description = ""; private float price = 0f; public String getDescription() { return description + "-" + this.price; } public void setDescription(String description) { this.description = description; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } //单品中返回价格,调料中要加上单品价格 public abstract float cost(); }
//主体中间层 public class Coffee extends Drink { public float cost() { return super.getPrice(); } }
public class Decaf extends Coffee { public Decaf() { super.setDescription("Decaf"); super.setPrice(3.0f); } }
public class Espresso extends Coffee { public Espresso() { super.setDescription("Espresso"); super.setPrice(4.0f); } }
public class LongBlack extends Coffee { public LongBlack() { super.setDescription("LongBlack"); super.setPrice(5.0f); } }
public class ShortBlack extends Coffee { public ShortBlack() { super.setDescription("ShortBlack"); super.setPrice(6.0f); } }
//装饰者中间层 public class Decorator extends Drink { //可以是单品也可以是被包装过的单品 private Drink drink; public Decorator(Drink drink) { this.drink = drink; } public float cost() { //返回装饰者(调料)的价格+单品或者被包装过的单品的价格(被包装过的单品就是继承自装饰者的调料) return super.getPrice() + drink.cost(); } @Override public String getDescription() { return super.getDescription() + "&&" + drink.getDescription(); } }
public class Chocolate extends Decorator { public Chocolate(Drink drink) { super(drink); super.setDescription("Chocolate"); super.setPrice(3.0f); } }
public class Milk extends Decorator { public Milk(Drink drink) { super(drink); super.setDescription("Milk"); super.setPrice(2.0f); } }
public class Soy extends Decorator { public Soy(Drink drink) { super(drink); super.setDescription("Soy"); super.setPrice(1.0f); } }
测试代码:
public class CoffeeBar { public static void main(String[] args) { Drink order; order = new Decaf(); System.out.println("order price:" + order.cost()); System.out.println("order desc:" + order.getDescription()); System.out.println("***********************************"); order = new LongBlack(); order = new Milk(order); order = new Chocolate(order); order = new Chocolate(order); System.out.println("order2 price:" + order.cost()); System.out.println("order2 desc:" + order.getDescription()); } }