Java中对AbstractFactory和Prototype模式的替代方法
GOF的AbstractFactory模式提供了将使用实例与创建实例分离开的方法。以书中实现不同的look & feel的用户界面的代码为例,MotifyWidgetFactory的createWindow创建MotifWindow的实例,PMWidgetFactory创建PMWindow的实例,MotifWindow和PMWindow都是Window的派生类。
然而,之所以要使用上述方法,仅仅是因为创建实例时选取的class不同。如果将class名称看作参数,我们完全可以使用同一个Factory代替众多的XXFactory:
WindowFactory.createWindow( String implementation_name )
如,MotifWindow win = factory.createWindow("Motif")
进一步考虑,之所以有众多createXX方法,也仅仅是因为需要创建不同的实例的class不同。因此我们可以进一步用下面的方法代替大部分createXX:
WidgetFactory.createWidget( String class_name, String implementation_name)
如,
MotifyWindow win = (MotifyWindow)factory.createWidget( "Window", "Motif")
PMScrollBar b = (PMScrollBar)factory.createWidget("ScrollBar", "PM")
C++没有标准的运行时期根据类名创建编译时期不存在的class实例的方法,因此有AbstractFactory这样的模式出现。但是java的reflection机制使得我们很容易实现上面的方法。如:
Widget createWidget(String class_name, String implementation_name){
//假设package_name是WidgetFactory的一个成员,用于保存需要创建的class的package名称
try{
return (Widget)Class.forName(package_name + '.' + implementation_name + class_name).newInstance();
} catch(Throwable t){
return null;
}
}
这样做的优点是,不需要为每一种look&feel的实现都派生一个Factory的子类。缺点是,通过reflect创建实例比直接new创建的性能要差。考虑到JDK1.4已经将这种性能差距减小到可以接受的程度,使用reflection代替AbstractFactory在大部分情况下还是可行的。
只要简单地约定同一look&feel实现中,子类的名称都用look&feel的名称+抽象父类的名称就可以了。
Prototype模式同样是解决运行时期创建一个编译时期不存在的类的实例的问题,不过是通过调用预先注册的这个类的一个实例的clone方法,返回这个实例的一份复制来实现。同样,通过java的reflection机制,大部分情况下我们也不需要应用这种模式,除非会带来很大的性能问题。
实际上C++同样可以实现这样的功能。例如COM就能够通过指定class id来创建某个class的实例,只不过在java中这属于内建的功能,使用起来更加方便一些。