参考文章:
http://blog.csdn.net/hust_is_lcd/article/details/7884320
http://blog.csdn.net/hguisu/article/details/7531960
定义:
是指对一个类的功能进行扩展,同时保证不修改原类的代码。(遵循开闭原则)
解决的问题:
- 需要动态地扩展一个类的功能时,非常灵活,可增可消。(注意,继承只能静态地扩展,无法消去)。
- 装饰模式用于弥补类继承模式无法遵循里氏代换原则的不足。
模式组成:
抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,
即可以给这些对象动态地添加职责。
具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。
可以给这个类的对象添加一些职责
抽象装饰器(Decorator):维持一个指向构件Component对象的实例,
并定义一个与抽象组件角色Component接口一致的接口
具体装饰器角色(ConcreteDecorator):向组件添加职责。
uml类图:
优点:
- 动态的扩展一个类的功能,可增加可删除。(继承只能增加功能,无法删除)
- 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
- 弥补类继承模式无法遵循里氏代换原则的不足。
- 避免在层次结构高层的类有太多的特征 。Decorator模式提供了一种“即用即付”的方法来添加职责
应用场景:
- 需要在不影响其他对象的情况下,以动态、透明的方式给对象添加职责
- 如果不适合使用子类来进行扩展的时候,可以考虑使用装饰器模式
Java中的IO是明显的装饰器模式的运用。FilterInputStream,FilterOutputStream,FilterRead,FilterWriter分别为具体装饰器的父类,相当于Decorator类,它们分别实现了InputStream,OutputStream,Reader,Writer类(这些类相当于Component,是其他组件类的父类,也是Decorator类的父类)。继承自InputStream,OutputStream,Reader,Writer这四个类的其他类是具体的组件类,每个都有相应的功能,相当于ConcreteComponent类。而继承自FilterInputStream,FilterOutputStream,FilterRead,FilterWriter这四个类的其他类就是具体的装饰器对象类,即ConcreteDecorator类。通过这些装饰器类,可以给我们提供更加具体的有用的功能。如FileInputStream是InputStream的一个子类,从文件中读取数据流,BufferedInputStream是继承自FilterInputStream的具体的装饰器类,该类提供一个内存的缓冲区类保存输入流中的数据。我们使用如下的代码来使用BufferedInputStream装饰FileInputStream,就可以提供一个内存缓冲区来保存从文件中读取的输入
装饰器模式vs代理模式
相同点:实现基本相同
区别:
- 代理模式中,代理类对被代理的对象有控制权,决定其执行或者不执行。
- 装饰模式中,装饰类对代理对象没有控制权,只能为其增加一层装饰,以加强被装饰对象的功能,仅此而已。
举个栗子:
定义抽象角色
abstract class Food { public abstract String getDesc(); }
定义抽象装饰器
abstract class FoodDecoration extends Food { @Override public abstract String getDesc(); }
定义具体的角色
class Duck extends Food { @Override public String getDesc() { return "鸭肉"; } }
定义具体装饰器
class RoastFood extends FoodDecoration { private Food food; public RoastFood(Food f) { this.food = f; } @Override public String getDesc() { return getDecoration() + food.getDesc(); } private String getDecoration() { return "烤"; } }
定义具体装饰器
class SteamedFood extends FoodDecoration { private Food food; public SteamedFood(Food f) { this.food = f; } @Override public String getDesc() { return getDecoration() + food.getDesc(); } private String getDecoration() { return "蒸"; } }
客户端调用
public static void main(String[] args) { // 创建食物 Food food = new Duck(); // 加入修饰者 RoastFood rf = new RoastFood(food); System.out.println(rf.getDesc()); // 加入又一个修饰者 SteamedFood sf = new SteamedFood(rf); System.out.println(sf.getDesc()); }
输出