小A:“那我们应该如何使用它哩?”
大B:“举Adapter中的打桩示例,在Adapter中有两种类:方形桩、圆形桩,Adapter模式展示如何综合使用这两个类,在Decorator模式中,我们是要在打桩时增加一些额外功能,比如,挖坑。在桩上钉木板等,不关心如何使用两个不相关的类。”
我们先建立一个接口:
publicinterfaceWork
{
publicvoidinsert();
}
接口Work有一个具体实现:插入方形桩或圆形桩,这两个区别对Decorator是无所谓。我们以插入方形桩为例:
publicclassSquarePegimplementsWork{
publicvoidinsert(){
System.out.println(“方形桩插入”);
}
}
大B:“现在有一个应用:需要在桩打入前,挖坑,在打入后,在桩上钉木板,这些额外的功能是动态,可能随意增加调整修改,比如,可能又需要在打桩之后钉架子,只是比喻。那么我们使用Decorator模式,这里方形桩SquarePeg是decoratee被刷油漆者,我们需要在decoratee上刷些‘油漆’,这些油漆就是那些额外的功能。”
publicclassDecoratorimplementsWork{
privateWorkwork;
//额外增加的功能被打包在这个List中
privateArrayListothers=newArrayList();
//在构造器中使用组合new方式,引入Work对象;
publicDecorator(Workwork)
{
this.work=work;
others.add(“挖坑”);
others.add(“钉木板”);
}
publicvoidinsert(){
newMethod();
}
//在新方法中,我们在insert之前增加其他方法,这里次序先后是用户灵活指定的
publicvoidnewMethod()
{
otherMethod();
work.insert();
}
publicvoidotherMethod()
{
ListIteratorlistIterator=others.listIterator();
while(listIterator.hasNext())
{
System.out.println(((String)(listIterator.next()))+“正在进行”);
}
}
}
大B:“在刚才讲的例子中,我们把挖坑和钉木板都排在了打桩insert前面,这里只是举例说明额外功能次序可以任意安排。好了,Decorator模式出来了,我们看如何调用。”
WorksquarePeg=newSquarePeg();
Workdecorator=newDecorator(squarePeg);
decorator.insert();
Decorator模式至此完成。
大B:“如果你细心,会发现,上面调用类似我们读取文件时的调用。”
FileReaderfr=newFileReader(filename);
BufferedReaderbr=newBufferedReader(fr);
大B:“实际上Java的I/OAPI就是使用Decorator实现的,I/O变种很多,如果都采取继承方法,将会产生很多子类,显然相当繁琐。Jive中的Decorator实现,在论坛系统中,有些特别的字是不能出现在论坛中如‘打倒XXX’,我们需要过滤这些‘反动’的字体。不让他们出现或者高亮度显示。在IBMJava专栏中专门谈Jive的文章中,有谈及Jive中ForumMessageFilter.java使用了Decorator模式,其实,该程序并没有真正使用Decorator。我们在分辨是否真正是Decorator模式,以及会真正使用Decorator模式,一定要把握好Decorator模式的定义,以及其中参与的角色(Decoratee和Decorator)。”
大B:“若你学过面向对象的php开发,即使很短的时间了解了一些,你会知道,你可以通过继承改变或者增加一个类的功能,这是所有面向对象语言的一个基本特性。如果已经存在的一个php类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继承这个类来产生一个新类-这建立在额外的代码上。但是产生子类并不总是可能或是合适的。”
小A:“如果改变一个已经初始化的对象的行为,怎么办?或者,继承许多类的行为,又怎么办?”
大B:“前一个,只能在于运行时完成,后者显然时可能的,但是可能会导致产生大量的不同的类-可怕的事情。”
小A:“你如何组织你的代码使其可以容易的添加基本的或者一些很少用到的特性,而不是直接不额外的代码写在你的类的内部?”
大B:“装饰器模式提供了改变子类的灵活方案。装饰器模式允许你在不引起子类数量爆炸的情况下动态的修饰对象,添加特性。当用于一组子类时,装饰器模式更加有用。”
小A:“如果拥有一族子类(从一个父类派生而来),需要在与子类独立使用情况下添加额外的特性,是否可以使用装饰器模式,以避免代码重复和具体子类数量的增加?”
大B:“看看以下例子,你可以更好的理解这种观点。考虑一个建立在组件概念上的‘form’表单库,在那里你需要为每一个你想要表现的表单控制类型建立一个类。这种类图SelectandTextInput类是组件类的子类。假如想要增加一个‘labeled’带标签的组件——一个输入表单告诉你要输入的内容。因为任何一个表单都可能需要被标记,可能会像这样继承每一个具体的组件。”
小A:“确实,装饰器模式是避免这种情况的好方法。”
大B:“装饰器模式结构上类似与代理模式。一个装饰器对象保留有对对象的引用,而且忠实的重新建立被装饰对象的公共接口。装饰器也可以增加方法,扩展被装饰对象的接口,任意重载方法,甚至可以在脚本执行期间有条件的重载方法。”
小A:“那是为什么?”
大B:“为了探究装饰器模式,可以用装饰器模式而不是继承,实现‘lable’和‘invalidation’两个特性。”