咖啡存在不停的种类,如Espresso、ShortBlack、LongBlack、Decaf。同时也有不同的调料,如Milk、Soy、Chocolate。此时用户可以单点咖啡,也可以点咖啡+调料,请计算费用
1.传统方法
1.1 方案1
每出现一种组合就实现一个类。这样当增加一个咖啡种类或者一个新的调料,类的数量就会倍增,就会出现类爆炸
1.2 方案2
将调料内置到Drink类。这样减少了类的数量,但是增加或者删除调料种类时,代码的维护量很大
2.装饰者模式
2.1 介绍
-
动态的将新功能附加到对象上
-
在对象功能扩展方面,它比继承更有弹性
-
体现了开闭原则(ocp)
2.2 原理
相当于打包一个快递。方案2是将调料类往咖啡类中添加,装饰者模式是将咖啡类往调料类中添加
当需要增加一个咖啡种类时,只需要多实现一个继承Coffee类的子类即可
Component
:主体,即被装饰者,属于抽象类ConcreteComponent
:具体的主体,即各种咖啡,继承主体Decorator
:装饰者,即各种调料(它也是主体的子类)
递归计算价格如下图所示:
2.3 代码实现
// 主体
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;
}
// 这个方法不仅咖啡类需要实现,调料类也需要实现,所以调料类需要继承Drink
public void setPrice(float price) {
this.price = price;
}
// 计算费用的抽象方法
// 子类来实现
public abstract float cost();
}
// 将共有的部分提取出来的一个缓冲层,可写可不写
public class Coffee extends Drink {
@Override
public float cost() {
return super.getPrice();
}
}
// 具体的主体
public class LongBlack extends Coffee {
public LongBlack() {
setDes("longblack");
setPrice(5.0f);
}
}
// 其他咖啡类的实现类似
// 装饰者
public class Decorator extends Drink {
private Drink obj; // 被装饰者
public Decorator(Drink obj) { // 组合,即将咖啡类往调料类中添加
this.obj = obj;
}
@Override
public float cost() {
// getPrice获取调料自己的价格
return getPrice() + obj.cost();
}
@Override
public String getDes() {
// obj.getDes() 输出被装饰者的信息
return des + " " + getPrice() + " && " + obj.getDes();
}
}
// 具体装饰者
public class Milk extends Decorator {
public Milk(Drink obj) {
super(obj);
setDes("牛奶");
setPrice(2.0f);
}
}
// 其他调料类的实现类似
public class CoffeeBar {
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 加入一份牛奶 描述 = " + order.getDes());
// 3.再加入一份牛奶
order = new Milk(order);
System.out.println("order 再加入一份牛奶 费用 =" + order.cost());
System.out.println("order 再加入一份牛奶 描述 = " + order.getDes());
}
}
参考
https://www.bilibili.com/video/BV1G4411c7N4?p=71-76