装饰者模式介绍:动态的将新功能附加到对象上。在对象的功能拓展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(opc原则)。
装饰者模式类似于打包一个快递。
主体(Component):陶瓷、衣服。
包装(Decorator):报纸填充、塑料泡沫、纸板、木板。
这边的Component主体一般是抽象的,因为具体的主体肯定是不少的,所以编码中一般是抽象类,具体子类ConcreteComponent继承这个抽象类(如果具体主体的分类超级多,中间可以再加层抽象类作为缓冲层,提取相同的部分)。Decorator也是需要继承主体类并聚合一个主体类。
以上说法十分抽象,例如有个例子:
1、咖啡店有很多咖啡总类,Espresso, ShortBlack,LongBlack, Decaf。
2、调料,milk(牛奶), soy(豆浆), chocolate(巧克力)
假如我点了一份LongBlack,点了两个巧克力和牛奶作为调料。现在需要用装饰者模式实现订单的组合以计算费用。我们便以上面描述的装饰者模式的思路来用代码实现。
Drink.java
public abstract class Drink { //描述 public String des; //价格 private float price = 0.0f; public String getDes() { return des; } public void setDes(String des) { this.des = des; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } //计算费用的方法 public abstract float cost(); }
Coffee.java
public abstract class Coffee extends Drink { @Override public float cost() { return super.getPrice(); } }
这边的coffee就相当于上面说的缓冲层,因为,drink还分很多种,有果汁、茶、咖啡。
LongBlack.java(这个是具体的咖啡)
public class LongBlack extends Coffee{ public LongBlack(){ setDes("LongBlack"); setPrice(5.0f); } }
Decorator.java
public class Decorator extends Drink { private Drink obj; public Decorator(Drink obj) { this.obj = obj; } @Override public float cost() { //先拿到自己的价格 return super.getPrice() + obj.cost(); } @Override public String getDes() { //返回自己的信息加被装饰者的信息 return super.getDes() + " " + super.getPrice() + " && " + obj.getDes(); } }
Chocolate.java
public class Chocolate extends Decorator { public Chocolate(Drink obj) { super(obj); setDes("巧克力"); setPrice(3.0f); } }
Milk.java
public class Milk extends Decorator { public Milk(Drink obj) { super(obj); setDes("牛奶"); setPrice(2.0f); } }
Client.java
public class Client { public static void main(String[] args) { //1、先点一份LongBlack Drink order = new LongBlack(); System.out.println("费用1=" + order.cost()); System.out.println("描述=" + order.getDes()); //2、加入一份牛奶 order = new Milk(order); System.out.println("order 加入一份牛奶后 费用=" + order.cost()); System.out.println("描述=" + order.getDes()); //3、加入一份巧克力 order = new Chocolate(order); System.out.println("order 加入一份巧克力后 费用=" + order.cost()); System.out.println("描述=" + order.getDes()); //4、加入一份巧克力 order = new Chocolate(order); System.out.println("order 加入一份巧克力后 费用=" + order.cost()); System.out.println("描述=" + order.getDes()); } }
输出的结果:
费用1=5.0 描述=LongBlack order 加入一份牛奶后 费用=7.0 描述=牛奶 2.0 && LongBlack order 加入一份巧克力后 费用=10.0 描述=巧克力 3.0 && 牛奶 2.0 && LongBlack order 加入一份巧克力后 费用=13.0 描述=巧克力 3.0 && 巧克力 3.0 && 牛奶 2.0 && LongBlack
在代码可以看出来,以上LongBlack(主体)中的getDes()和cost()是直接返回,Decorator实例中的getDes()和cost()主要是递归的形式,遇到具体的主体,递归停止。