装饰者模式
装饰者模式
星巴克咖啡订单项目:
1)咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack(浓缩咖啡)、LongBlack(美式咖啡)、Decaf(无因咖啡)
2)调料:Milk、Soy(豆浆)、Chocolate
3)要求在扩展新的咖啡种类的时候,具有良好的扩展性、改动方便、维护方便。
4)使用OO(面向对象)的方法来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以点单品咖啡+调料组合。
方案一 较差的传统方案
这种解决方案会造成类爆炸
方案二 对方案一进行改进
前面分析到方案一因为咖啡单品+调料组合会造成类爆炸,因此可以做改进,将调料内置到Drink类中,这样就不会造成类的数量过多。从而提高了代码的可维护性。
说明:milk,soy.chocolate可以设计为boolean类型,表示是否需要添加相应的调料。
方案二问题分析:
- 方案二可以控制类的数量,不至于造成类的数量过多。
- 在增加或者删除调料类的时候,代码的维护量很大(因为都要在同一个Drink类中进行修改)
- 考虑到用户可以添加多份调料的时候,可以将hasMilk 返回一个对应的int 类型
- 所以我们考虑使用装饰者模式
装饰者模式定义
代码演示:
package com.sky.decorator; /** * 将各种单品咖啡做一个缓存层 */ public class Coffee extends Drink { @Override public float cost() { return super.getPrice(); } } package com.sky.decorator; /** * 意大利咖啡 要继承缓存层 */ public class Espresso extends Coffee { // 通过构造器,初始化意大利咖啡 描述 和 价格 public Espresso(){ setDes(" 意大利咖啡 "); setPrice(6.0f); } } package com.sky.decorator; /** * 美式咖啡 */ public class LongBlack extends Coffee { public LongBlack(){ setDes(" 美式咖啡 "); setPrice(5.0f); } } package com.sky.decorator; /** * 浓缩咖啡 单品咖啡 */ public class ShortBlack extends Coffee { public ShortBlack(){ setDes(" 浓缩咖啡 "); setPrice(4.0f); } } package com.sky.decorator; /** * 无因咖啡 */ public class Decaf extends Coffee { public Decaf(){ setDes(" 无因咖啡 "); setPrice(3.0f); } } package com.sky.decorator; /** * 抽象类 */ public abstract class Drink { private String des; // 描述 private float price = 0.0f; // 价格 // 添加set get 方法 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(); } package com.sky.decorator; /** * 装饰者 */ public class Decorator extends Drink { private Drink obj; // 被装饰者 public Decorator(Drink obj){ // 体现的是一种组合关系 this.obj = obj; } @Override public float cost() { // super.getPrice() 表示自己的价格,其中super.是可以不写的 return super.getPrice() + obj.cost(); } @Override public String getDes() { // 其中super.是可以不写的 // obj.getDes() 表示输出被装饰者的信息 return super.getDes() + " " + super.getPrice() + " " + obj.getDes() + " " + obj.getPrice(); } } package com.sky.decorator; /** * 调味品 巧克力 */ public class Chocolate extends Decorator { public Chocolate(Drink obj) { super(obj); setDes(" 巧克力 "); setPrice(3.0f); } } package com.sky.decorator; /** * 调味品 牛奶 */ public class Milk extends Decorator { public Milk(Drink obj) { super(obj); setDes(" 牛奶 "); setPrice(2.0f); } } package com.sky.decorator; /** * 调味品 豆浆 */ public class Soy extends Decorator { public Soy(Drink obj) { super(obj); setDes(" 豆浆 "); setPrice(1.5f); } } package com.sky.decorator; public class CoffeeBar { public static void main(String[] args) { // 使用装饰者模式点一份美式咖啡和两份牛奶 // 1.先点一份美式咖啡 Drink order = new LongBlack(); System.out.println(" 描述:" + order.getDes()); System.out.println(" 费用:" + order.cost()); // 2.再加一份牛奶 order = new Milk(order); System.out.println(" 描述:" + order.getDes()); System.out.println(" 费用:" + order.cost()); // 3.再加入一份巧克力 order = new Chocolate(order); System.out.println(" 描述:" + order.getDes()); System.out.println(" 费用:" + order.cost()); // 3.再加入一份巧克力 order = new Chocolate(order); System.out.println(" 描述:" + order.getDes()); System.out.println(" 费用:" + order.cost()); System.out.println("==================================="); System.out.println("==================================="); Drink order2 = new Decaf(); System.out.println(" 描述:" + order2.getDes()); System.out.println(" 费用:" + order2.cost()); order2 = new Milk(order2); System.out.println(" 描述:" + order2.getDes()); System.out.println(" 费用:" + order2.cost()); } } 描述: 美式咖啡 费用:5.0 描述: 牛奶 2.0 美式咖啡 5.0 费用:7.0 描述: 巧克力 3.0 牛奶 2.0 美式咖啡 5.0 2.0 费用:10.0 描述: 巧克力 3.0 巧克力 3.0 牛奶 2.0 美式咖啡 5.0 2.0 3.0 费用:13.0 =================================== =================================== 描述: 无因咖啡 费用:3.0 描述: 牛奶 2.0 无因咖啡 3.0 费用:5.0