目录
项目需求
方案一
分析
方案二
分析
装饰者模式
装饰者模式下的订单:2份巧克力+一份牛奶的LongBlack
UML类图
代码实现
装饰者模式在JDK应用的源码分析
星巴克咖啡订单项目(咖啡馆)
咖啡种类/单品咖啡: Espresso(意大利浓咖啡), ShortBlack, LongBlack(美式咖啡), Decaf(无因咖啡)调料:Milk Soy(豆浆) Chocolate要求在扩展新的咖啡种类时,具有良好的扩展性,改动方便,维护方便使用OO来计算不同种类咖啡的费用:客户可以点单品咖啡,也可以点单品咖啡+调料组合方案一组合会造成类的倍增,因此可以做改进,将调料内置到Drink类,这样就不会造成类数量过多。从而提高项目的可维护性。
milk、soy、chocolate可以设计为Boolean,表示是否要添加相应的调料
<1>装饰者模式就像打包一个快递
主体:比如:陶瓷、衣服(Component) //被装饰者包装: 比如: 报纸填充、塑料泡沫、纸板、木板(Decorator)<2>Component
主体:比如类似前面的Drink<3>ConcreteComponent:具体的主体,如:前面的各个单品咖啡; Decorator:装饰者,比如各调料
<4>在上图的Component和ConcreteComponent之间,如果ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象成一个类。
1)Drink类就是前面说的抽象类,Component
2) ShortBlack就是单品咖啡
3) Decorator是一个装饰类,含有一个被装饰的对象(Drink obj)
4)Decorator的cost方法进行一个费用的叠加计算,递归的计算价格
说明
1) Milk包含了LongBlack
2)一份Chocolate包含了(Milk + LongBlack)
3)一份Chocolate包含了(Chocolate+Milk+LongBlack)
4)这样不管是什么形式的单品咖啡+调料组合,通过递归方式可以方便的组合和维护
Drink
package decorator; 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; } public void setPrice(float price) { this.price = price; } //计算费用的抽象方法:由子类来实现 public abstract float cost(); }Coffee
package decorator; public class Coffee extends Drink{ @Override public float cost() { return super.getPrice(); } }LongBlack && Espresso && ShortBlack
package decorator; public class LongBlack extends Coffee{ public LongBlack(){ setDes("美式咖啡"); setPrice(5.0f); } } package decorator; public class Espresso extends Coffee{ public Espresso(){ setDes("意大利咖啡"); setPrice(6.0f); } } package decorator; public class ShortBlack extends Coffee{ public ShortBlack(){ setDes("shortblack"); setPrice(4.0f); } }Decorator
package decorator; 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() { //obj.getDes():被装饰者的信息 return super.des + " " + super.getPrice() + " && " + obj.getDes(); } }Chocolate && Milk && Soy
package decorator; //具体的Decorator,这里就是调味品 public class Chocolate extends Decorator{ public Chocolate(Drink obj) { super(obj); setDes(" 巧克力 "); setPrice(3.0f);//调味品的价格 } } package decorator; //具体的Decorator,这里就是调味品 public class Milk extends Decorator{ public Milk(Drink obj) { super(obj); setDes(" 牛奶 "); setPrice(2.0f);//调味品的价格 } } package decorator; //具体的Decorator,这里就是调味品 public class Soy extends Decorator{ public Soy(Drink obj) { super(obj); setDes(" 豆浆 "); setPrice(1.5f);//调味品的价格 } }客户端使用CoffeeBar
package decorator; public class CoffeeBar { public static void main(String[] args) { //装饰者模式下的订单:2份巧克力+1份牛奶的LongBlack //1.点一份LongBlack Drink order = new LongBlack(); System.out.println("描述=" + order.getDes() + " && " + "费用=" + order.cost()); //2.order加入一份牛奶 order = new Milk(order); System.out.println("描述=" + order.getDes() + " && " + "费用=" + order.cost()); //3.加入一份巧克力 order = new Chocolate(order); System.out.println("描述=" + order.getDes() + " && " + "费用=" + order.cost()); //4.再加入一份巧克力 order = new Chocolate(order); System.out.println("描述=" + order.getDes() + " && " + "费用=" + order.cost()); } }如果要添加一个无因咖啡的话,只需要让DeCaf去继承Coffee就可以了
DeCaf
package decorator; public class DeCaf extends Coffee{ public DeCaf(){ setDes("无因咖啡"); setPrice(1.0f); } }CoffeeBar中添加
//第二个订单 Drink order2 = new DeCaf(); System.out.println("order2 无因咖啡 费用=" + order2.cost()); System.out.println("order2 无因咖啡 描述=" + order2.getDes()); //加一份牛奶 order2 = new Milk(order2); System.out.println("order2 无因咖啡 加入一份牛奶 费用=" + order2.cost()); System.out.println("order2 无因咖啡 加入一份牛奶 描述=" + order2.getDes());public abstract class InputStream implements Closeable{} public class FilterInputStream extends InputStream{ //是一个装饰者类 Decorator protected volatile InputStream in//被装饰的对象 } class DataInputStream extends FilterInputStream implements DataInputStream{//FilterInputStream子类,也继承了被装饰的对象 } DataInputStream dis = new DataInputStream(new FileInputStream("d:\\abc.txt")); System.out.println(dis.read()); dis.close(); 1. InputStream是抽象类,类似于Drink2. FileInputStream是InputStream的子类,类似之前的DeCaf、LongBlack3. FilterInputStream是InputStream子类,类似前面的Decorator4. DataInputStream是FilterInputStream子类,是具体的修饰者,类似前面的Coffee、Milk、Soy5. FilterInputStream类有protected volatile InputStream in;即含被装饰者6. 分析得出,在JDK的io体系中,就是使用了装饰者模式