装饰者模式
1.简介
要求
咖啡种类/单品咖啡:Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡)
调料: Milk、Soy(豆浆)、Chocolate
要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
使用OO的来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以单品咖啡+调料组合。
方案一
Drink是一个抽象类,表示饮料
des 就是对咖啡的描述,比如咖啡的名字
cost()方法就是计算费用,Drink类中做成一个抽象方法.
Decaf 就是单品咖啡,继承 Drink,并实现cost
Espress && Milk就是单品咖啡+调料,这个组合很多
问题:这样设计,会有很多类,当我们增加一个单品咖啡,或者一个新的调料,类的数量就会倍增,就会出现类爆炸
方案二
将调料内置Drink中
方案2-解决星巴克咖啡订单问题分析
1)方案2可以控制类的数量,不至于造成很多的类
2)在增加或者删除调料种类时,代码的维护量很大
3)考虑到用户可以添加多份调料时,可以将 hasMilk返回一个对应int
4)考虑使用装饰者模式
装饰者模式定义
装饰者模式原理
装饰者模式就像打包一个快递
- 主体:比如:陶瓷、衣服(Component)//被装饰者
包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
- Component主体:比如类似前面的Drink
- ConcreteComponent和 Decorator
ConcreteComponent:具体的主体,比如前面的各个单品咖啡
Decorator:装饰者,比如各调料.
- 在Component与ConcreteComponent之间,如果ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。
2.案例

Drink类
1 2 3 4 5 6 7 8
| @Data public abstract class Drink { public String des; private float price = 0.0f; public abstract float cost(); }
|
Coffee类
1 2 3 4 5 6 7
| public class Coffee extends Drink{
@Override public float cost() { return super.getPrice(); } }
|
两种单品咖啡
1 2 3 4 5 6
| public class Espresso extends Coffee{ public Espresso(){ setDes("意大利咖啡"); setPrice(6.0f); } }
|
1 2 3 4 5 6 7
| public class LongBlack extends Coffee {
public LongBlack(){ setDes("longback"); setPrice(5.0f); } }
|
装饰器类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| 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.des + " " + super.getPrice() + "&&" + obj.getDes(); } }
|
具体装饰器类
1 2 3 4 5 6 7 8
| public class Chocolate extends Decorator { public Chocolate(Drink obj) { super(obj); setDes("巧克力"); setPrice(3.0f); } }
|
1 2 3 4 5 6 7
| public class Milk extends Decorator { public Milk(Drink obj) { super(obj); setDes("牛奶"); setPrice(2.0f); } }
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class CoffeeBar { public static void main(String[] args) { Drink order = new LongBlack(); System.out.println("费用:"+order.cost()); System.out.println("描述:"+order.getDes()); order = new Milk(order); System.out.println("费用:"+order.cost()); System.out.println("描述:"+order.getDes()); order = new Chocolate(order); System.out.println("费用:"+order.cost()); System.out.println("描述:"+order.getDes()); } }
|
3.在JDK中的使用
Java中IO结果FilterputStream是一个装饰者者
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import java.io.DataInputStream; import java.io.FileInputStream; import java.io.InputStream; public class Decorator { public static void main(String[] args) throws Exception {
DataInputStream dis =new DataInputStream(new FileInputStream(" d:llabc.txt"));System.out.println(dis.read()); dis.close(); } }
|