1. 概述
若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性。如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类—这建立在额外的代码上。
通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。如果 你希望改变一个已经初始化的对象的行为,你怎么办?或者,你希望继承许多类的行为,改怎么办?前一个,只能在于运行时完成,后者显然时可能的,但是可能会导致产生大量的不同的类—可怕的事情。
2. 问题
你如何组织你的代码使其可以容易的添加基本的或者一些很少用到的 特性,而不是直接不额外的代码写在你的类的内部?
3. 解决方案
装饰器模式:动态地给一个对象添加一些额外的职责或者行为。就增加功能来说, Decorator模式相比生成子类更为灵活。
装饰器模式提供了改变子类的灵活方案。装饰器模式在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
当用于一组子类时,装饰器模式更加有用。如果你拥有一族子类(从一个父类派生而来),你需要在与子类独立使用情况下添加额外的特性,你可以使用装饰器模式,以避免代码重复和具体子类数量的增加。
4. 适用性
以下情况使用Decorator模式
1)• 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
2)• 处理那些可以撤消的职责。
3)• 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,
为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
5. 结构
装饰器涉及四个名词
1、接口或者抽象基类
2、被装饰对象,也就是一个简单的实现了1中提到的接口或者抽象基类的实现类。
3、装饰对象,就是去装饰被装饰对象的对象
4、继承装饰对象类的子类,也就是具体的装饰器类了。
说了这么多,估计你基本跟没听说过一样。好了,来段代码,看看
/这是第一类名词 public interface IDecorate { public void sayHello(); } //这是第二类名词 public class DecorateImpl implements IDecorate { public void sayHello() { System.out.print("Hello"); } } //这是第三类名词,真正的装饰器就在这里开始了,也是所有欲实现装饰器的父类 public class Decorate implements IDecorate { //声明一个被装饰的对象 private IDecorate decorate; //被装饰对象从装饰器的构造函数中传进来(必须这样做) public Decorate(IDecorate decorate) { this.decorate = decorate; } //在基类装饰器中只调用被装饰对象的方法 public void sayHello() { decorate.sayHello(); } } 再对这个装饰器的基类说明一下,在每个装饰器模式中,这个类的结构基本不变 或者说这上面是装饰器第三类名词中最小的类了,必须有以上定义的这些元素。 //这是第四类名词,装饰就看这里了 public class SimpleDecorate extends Decorate { public Decorate(IDecorate decorate) { super(decorate); } //开装饰了哦。。。 public void sayHello() { //在原来的方法中加入了sayChina方法。 sayChina(); super.sayHello(); //在原来的方法中加入了sayWorld方法。 sayWorld(); } public void sayChina() { System.out.print("China, "); } public void sayWorld() { System.out.print(" World!\n"); } } //来,测试一下 public void TestDecorate() { //不使用装饰器 public static void unUseDecorate(IDecorate decorate) { //输出 Hello decorate.sayHello(); } //使用装饰器 public static void useDecorate(IDecorate decorate) { IDecorate simpleDecorate = new SimpleDecorate(decorate); //要调用装饰了的方法 //输出 China, Hello World! simpleDecorate.sayHello(); } public static void main(String[] argv) { IDecorate decorate = new DecorateImpl(); } } //是不是发现,原来只输出的hello的方法被装饰后,在其前和其后分别输出了china和world啦。
6.构建模式的组成
抽象组件角色(IDecorate):定义一个对象接口,以规范准备接受附加责任的对象,
即可以给这些对象动态地添加职责。
具体组件角色(DecorateImpl) :被装饰者,定义一个将要被装饰增加功能的类。
可以给这个类的对象添加一些职责
抽象装饰器(Decorator):维持一个指向构件IDecorate对象的实例,
并定义一个与抽象组件角色IDecorate接口一致的接口
具体装饰器角色(SimpleDecorate):向组件添加职责。
7. 效果
装饰模式的特点:
(1) 装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
(2) 装饰对象包含一个真实对象的索引(reference)
(3) 装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。
(4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
Decorator模式使用场景:
1) 比静态继承更灵活: 与对象的静态继承(多重继承)相比, Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新的类,并且会增加系统的复杂度。1、装饰器模式主要装饰供外部调用的接口方法,如果一个接口方法只是提供给内部调用,则不能使用该模式。
2、装饰器模式主要装饰可能要改变的接口方法,如果类中的某种行为在将来可能发生变化,而你又懒得去改变
原来的类,那么就可以考虑使用装饰器模式了。
8.总结
1)使用装饰器设计模式设计类的目标是: 不必重写任何已有的功能性代码,而是对某个基于对象应用增量变化。
2) 装饰器设计模式采用这样的构建方式: 在主代码流中应该能够直接插入一个或多个更改或“装饰”目标对象的装饰器,
同时不影响其他代码流。
3) Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,
而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。
也许装饰器模式最重要的一个方面是它的超过继承的能力。“问题”部分展现了一个使用继承的子类爆炸。
基于装饰器模式的解决方案,UML类图展现了这个简洁灵活的解决方案。
转自:http://blog.csdn.net/hguisu/article/details/7531960
http://www.cnblogs.com/octobershiner/archive/2011/11/04/2236730.html