装饰者模式
装饰者模式
星巴克咖啡订单项目:
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
浙公网安备 33010602011771号