以咖啡订单引入装饰者模式
- 咖啡种类:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
- 调料:Milk、Soy(豆浆)、Chocolate
客户可以点单品咖啡,也可以单品咖啡+调料组合。
方案一
比较差的设计样例,耦合度过高。
如果说要添加扩展新的单品咖啡或者组合口味的咖啡,类的数量增加,就会引发"类爆炸"。
方案二
将调料内置到Drink类,不会造成类数量过多。
但是,添加或者删除调味品的种类时,需要改动维护。
一、装饰者模式
1、基本介绍
动态的将新功能附加到对象上
在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)。
装饰者模式原理
装饰者模式就像打包一个快递
- 主体:比如:陶瓷、衣服 (Component) // 被装饰者
- 包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
Component 主体:比如类似前面的 Drink
ConcreteComponent:具体的主体, 比如前面的各个单品咖啡
Decorato:装饰者,比如各调料
如果 ConcreteComponent 类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象成一个类。
2、代码实现
思路分析
抽象类饮品
public abstract class Drink {
//对饮品的描述
private String description;
//价格
private float price;
//计算价格,由子类实现
public abstract float cost();
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
public void setPrice(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
}
缓冲类Coffee
public class Coffee extends Drink{
@Override
public float cost() {
return super.getPrice();
}
}
两种Coffee
public class LongBlackCoffee extends Coffee{
public LongBlackCoffee(){
setDescription("一份美式咖啡");
setPrice(7.0f);
}
}
public class ShortBlackCoffee extends Coffee {
public ShortBlackCoffee(){
setDescription("一份浓缩咖啡");
setPrice(5.0f);
}
}
装饰者Decorator
//装饰者
public class Decorator extends Drink{
//被装饰者;
private Drink drink;
public Decorator(Drink drink){
this.drink = drink;
}
@Override
public float cost() {
return super.getPrice() + drink.cost();
}
@Override
public String getDescription(){
return drink.getDescription() + " && " +
super.getDescription() + super.getPrice();
}
}
两种调味品
public class Milk extends Decorator{
public Milk(Drink drink) {
super(drink);
setDescription("一份牛奶");
setPrice(2.0f);
}
}
public class Chocolate extends Decorator{
public Chocolate(Drink drink) {
super(drink);
setDescription("一份巧克力");
setPrice(1.0f);
}
}
模拟客户下单
public class Client {
public static void main(String[] args) {
//两份巧克力+一份牛奶的美式咖啡;
//1.先点美式咖啡;
Drink result = new LongBlackCoffee();
System.out.println("步骤一::" + result.getDescription());
System.out.println("本次花费==>" + result.cost());
//2.加份牛奶;
result = new Milk(result);
System.out.println("步骤二::" + result.getDescription());
System.out.println("本次花费==>" + result.cost());
//3.加份巧克力;
result = new Chocolate(result);
System.out.println("步骤三::" + result.getDescription());
System.out.println("本次花费==>" + result.cost());
//4.加份巧克力;
result = new Chocolate(result);
System.out.println("步骤四::" + result.getDescription());
System.out.println("最终花费==>" + result.cost());
}
}
输出
步骤一::一份美式咖啡
本次花费==>7.0
步骤二::一份美式咖啡 && 一份牛奶2.0
本次花费==>9.0
步骤三::一份美式咖啡 && 一份牛奶2.0 && 一份巧克力1.0
本次花费==>10.0
步骤四::一份美式咖啡 && 一份牛奶2.0 && 一份巧克力1.0 && 一份巧克力1.0
最终花费==>11.0
二、装饰者模式在 JDK 应用的源码分析
Java 的 IO 结构,FilterInputStream 就是一个装饰者
public class Test {
public static void main(String[] args) throws IOException {
DataInputStream dataInputStream = new DataInputStream(new FileInputStream("e:\\a.txt"));
System.out.println(dataInputStream.read());
dataInputStream.close();
}
}
说明
- InputStream 是抽象类,类似前面的Drink
- FileInputStream是InputStream子类,类似前面的浓缩咖啡,美式咖啡
- FilterInputStream是InputStream子类,类似前面的Decorator修饰者
- DataInputStream是FilterInputStream子类,具体的修饰者,类似前面的Milk,Chocolate等
- FilterInputStream类有protected volatile InputStream in; 即含被装饰者
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream var1) {
this.in = var1;
}
分析得出在 JDK 的 IO 体系中,就是使用装饰者模式