装饰器模式(Decorator Pattern),也叫包装器模式(Wrapper Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
基本介绍
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
何时使用:在不想增加很多子类的情况下扩展类。
- 关键代码:
-
应用实例:
- 1、孙悟空有 72 变,当他变成"庙宇"后,他的根本还是一只猴子,但是他又有了庙宇的功能。
- 2、不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:多层装饰比较复杂。
- 使用场景:
注意事项:可代替继承。
概括
装饰者模式定义
@H_502_84@类图:
装饰者模式原理,角色分析
@H_502_84@主体:比如:陶瓷、衣服 (Component) //被装饰者
包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
Decorator 装饰者:装饰主体,比如盒子,比如后面的各调料。
在如图的 Component 与 ConcreteComponent 之间,如果 ConcreteComponent 类很多,还可以设计一个缓冲层,将共有的部分提取出来,抽象层一个类。
解释:陶瓷放在盒子中,盒子在外层装饰陶瓷,
装饰者套娃,一层包一层就是装饰(继承+聚合)
(聚合是为了装饰(new xxx(xxx)),而继承是为了套娃(new xxx(new xxx)))
我的理解
在不改变原有实体的情况下,对原有实体进行装饰。如 圆→红色的圆。
应用实例
星巴克咖啡订单项目(咖啡馆):
@H_502_84@使用传统方式
方案 1-解决星巴克咖啡订单项目
类图:
方案 1-解决星巴克咖啡订单问题分析
@H_502_84@方案 2-解决星巴克咖啡订单(好点)
@H_502_84@前面分析到方案 1 因为咖啡单品+调料组合会造成类的倍增,因此可以做改进,将调料内置到 Drink 类,这样就不会造成类数量过多。从而提高项目的维护性(如图)
说明: milk,soy,chocolate 可以设计为 Boolean,表示是否要添加相应的调料.
方案 2-解决星巴克咖啡订单问题分析
@H_502_84@使用装饰者模式
类图:
装饰者模式下的订单:2 份巧克力+一份牛奶的 LongBlack
装饰者模式咖啡订单项目应用实例
代码实现
Decorator
package com.nemo.decorator; public class Decorator extends Drink { private Drink obj; public Decorator(Drink obj) { //聚合 // TODO Auto-generated constructor stub this.obj = obj; } @Override public float cost() { // TODO Auto-generated method stub // getPrice 自己价格 return super.getPrice() + obj.cost(); } @Override public String getDes() { // TODO Auto-generated method stub // obj.getDes() 输出被装饰者的信息 return des + " " + getPrice() + " && " + obj.getDes(); } }
@H_502_231@Drink
package com.nemo.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(); }
@H_502_231@Coffee
package com.nemo.decorator; public class Coffee extends Drink { @Override public float cost() { // TODO Auto-generated method stub return super.getPrice(); } }
@H_502_231@DeCaf
package com.nemo.decorator; public class DeCaf extends Coffee { public DeCaf() { setDes(" 无因咖啡 "); setPrice(1.0f); } }
@H_502_231@Espresso
package com.nemo.decorator; public class Espresso extends Coffee { public Espresso() { setDes(" 意大利咖啡 "); setPrice(6.0f); } }
@H_502_231@LongBlack
package com.nemo.decorator; public class LongBlack extends Coffee { public LongBlack() { setDes(" longblack "); setPrice(5.0f); } }
@H_502_231@ShortBlack
package com.nemo.decorator; public class ShortBlack extends Coffee{ public ShortBlack() { setDes(" shortblack "); setPrice(4.0f); } }
@H_502_231@Chocolate
package com.nemo.decorator; //具体的 Decorator, 这里就是调味品 public class Chocolate extends Decorator { public Chocolate(Drink obj) { super(obj); setDes(" 巧克力 "); setPrice(3.0f); // 调味品 的价格 } }
@H_502_231@Milk
package com.nemo.decorator; public class Milk extends Decorator { public Milk(Drink obj) { // TODO Auto-generated constructor stub super(obj); setDes(" 牛 奶 "); setPrice(2.0f); } }
@H_502_231@Soy
package com.nemo.decorator; public class extends Decorator{ public Soy(Drink obj) { // TODO Auto-generated constructor stub super(obj); setDes(" 豆浆 "); setPrice(1.5f); } }
@H_502_231@CoffeeBar
package com.nemo.decorator; public class CoffeeBar { public static void main(String[] args) { // TODO Auto-generated method stub // 装饰者模式下的订单:2 份巧克力+一份牛奶的 LongBlack // 1. 点一份 LongBlack Drink order = new LongBlack(); System.out.println("费用 1=" + order.cost()); System.out.println("描述=" + order.getDes()); // 2. order 加入一份牛奶 order = new Milk(order); System.out.println("order 加入一份牛奶 费用 = " + order.cost()); System.out.println("order 加入一份牛奶 描述 = " + order.getDes()); // 3. order 加入一份巧克力 order = new Chocolate(order); System.out.println("order 加入一份牛奶 加入一份巧克力 费用 = " + order.cost()); System.out.println("order 加入一份牛奶 加入一份巧克力 描述 = " + order.getDes()); // 3. order 加入一份巧克力 order = new Chocolate(order); System.out.println("order 加入一份牛奶 加入 2 份巧克力 费用 = " + order.cost()); System.out.println("order 加入一份牛奶 加入 2 份巧克力 描述 = " + order.getDes()); System.out.println("==========================="); 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()); } }
@H_502_231@装饰者模式在 JDK 应用的源码分析
Java 的 IO 结构,FilterInputStream 就是一个装饰者
源码说明
package com.nemo.jdk; import java.io.DataInputStream; import java.io.FileInputStream; import java.io.InputStream; public class Decorator { public static void main(String[] args) throws Exception{ // TODO Auto-generated method stub //说明 //1. InputStream 是抽象类,类似我们前面讲的 Drink //2. FileInputStream 是 InputStream 子类,类似我们前面的 DeCaf,LongBlack //3. FilterInputStream 是 InputStream 子类,类似我们前面 的 Decorator 修饰者 //4. DataInputStream 是 FilterInputStream 子类,具体的修饰者,类似前面的 Milk,Soy 等 //5. FilterInputStream 类 有 protected volatile InputStream in; 即 含被装饰者 //6. 分析得出在 jdk 的 io 体系中,就是使用装饰者模式 DataInputStream dis = new DataInputStream(new FileInputStream("d:\\abc.txt")); System.out.println(dis.read()); dis.close(); } }
@H_502_231@