意图
动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator模式相比生成子类更为灵活。该模式以对客 户端透明的方式扩展对象的功能。
装饰模式的本质是动态组合。动态是手段,组合是目的。每个装饰类可以只负责添加一项额外功能,然后通过组合为被装饰类添加复杂功能。由于每个装饰类的职责比较简单单一,增加了这些装饰类的可重用性,同时也更符合单一职责原则。
适用环境
(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
(2)处理那些可以撤消的职责。
(3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的 子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
角色
l 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象
l 具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类
l 装饰角色(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口
l 具体装饰角色(ConcreteDecorator):负责给构件对象“贴上”附加的责任
类图
实例
1抽象接口:
1.1饮料:
public interface Beverage { public String getDesc(); public double getPrice(); }
2接口实现:
2.1奶茶:
public class Milktea implements Beverage { @Override public String getDesc() { System.out.println("--Milktea.desc"); return "奶茶"; } @Override public double getPrice() { System.out.println("--Milktea.price"); return 10; } }
2.2奶绿:
public class Milkgreen implements Beverage { @Override public String getDesc() { System.out.println("--Milkgreen.desc"); return "奶绿"; } @Override public double getPrice() { System.out.println("--Milkgreen.price"); return 8; } }
3装饰类:装饰者类内有一个真实对象的引用
public class Decorator implements Beverage { private Beverage beverage = null; public Decorator(Beverage beverage) { System.out.println("--Decorator.construct"); this.beverage = beverage; } @Override public String getDesc() { System.out.println("--Decorator.desc"); return beverage.getDesc(); } @Override public double getPrice() { System.out.println("--Decorator.price"); return beverage.getPrice();//价格 子类决定 } }
4继承装饰类(覆盖父类方法):
4.1红豆:
public class Redbean extends Decorator { private String desc = "加了红豆"; public Redbean(Beverage beverage) { super(beverage); } public String getDesc() { System.out.println("--Redbean.desc"); return super.getDesc() + desc + "的价钱:"; } public double getPrice() { System.out.println("--Redbean.price"); return super.getPrice() + 2; //2表示红豆的价格 } }
4.2布丁:
public class Pudding extends Decorator { private String desc = "加了布丁"; public Pudding(Beverage beverage) { super(beverage); } public String getDesc() { System.out.println("--Pudding.desc"); return super.getDesc() + desc + "的价钱:"; } public double getPrice() { System.out.println("--Pudding.price"); return super.getPrice() + 1;//1表示布丁的价格 } }
5测试:
public class Test { public static void main(String[] args) { Beverage beverage = new Milktea(); Redbean redbean = new Redbean(beverage); System.out.println(redbean.getDesc() + " " + redbean.getPrice()); Beverage rb = new Redbean(beverage); Beverage pb = new Pudding(rb); System.out.println(pb.getDesc() + " " + pb.getPrice());//混合 } }
6结果:
--Decorator.construct
--Redbean.desc
--Decorator.desc
--Milktea.desc
--Redbean.price
--Decorator.price
--Milktea.price
奶茶加了红豆的价钱:
12.0
--Decorator.construct
--Decorator.construct
--Pudding.desc
--Decorator.desc
--Redbean.desc
--Decorator.desc
--Milktea.desc
--Pudding.price
--Decorator.price
--Redbean.price
--Decorator.price
--Milktea.price
奶茶加了红豆的价钱:加了布丁的价钱:
13.0
JDK运用
JDK中的装饰者模式:java.io
FilterInputStream继承(实现)InputStream,同时BufferedInputStream继承了FilterInputStream
- 抽象构件:最顶层的基类InputStream(饮料)
- 具体构件:FileInputStream和ObjectInputStream等(奶茶)
- 装饰角色:FilterInputStream中有一个InputStream的实例和构造方法传入InputStream对象(装饰器)
public class FilterInputStream extends InputStream { protected volatile InputStream in; protected FilterInputStream(InputStream in) { this.in = in; }
- 具体装饰角色:BufferedInputStream中有构造方法传入InputStream对象,实现了装饰(红豆)
public BufferedInputStream(InputStream in) { this(in, defaultBufferSize); } public BufferedInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; }
Head First 设计模式(中文版)的示例:
码云地址:https://gitee.com/manusas/DecoratorDP