工厂设计的模式研究
2010-09-17欧建斌
欧建斌
0 引言
学习了面向对象分析设计编程思想,开始考虑通过封装、继承、多态把程序的耦合度降低,开始用设计模式使得程序更加的灵活,容易修改,并且易于复用。设计模式使人们可以更加简单方便地复用成功的设计和体系结构。将已证实的技术表述成设计模式也会使新系统开发者更加容易理解其设计思路。设计模式帮助你做出有利于系统复用的选择,避免设计损害了系统复用性。实际上,设计模式并不只是一种具体“技术”,它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧,让你能够真正掌握接口或抽象类的应用,从而在原来的语言基础上跃进一步,更重要的是,的设计模式反复向你强调一个宗旨:要让你的程序尽可能的可重用。
1 设计模式定义
模式(pattern)其实就是解决某一类问题的方法论。你把解决某类问题的方法总结归纳到理论高度,那就是模式。
Alexander给出的经典定义是:每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心。通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作。
模式有不同的领域,建筑领域有建筑模式,软件设计领域也有设计模式。当一个领域逐渐成熟的时候,自然会出现很多模式。随着这个领域相关文献的增多,出现了一些有用的设计模式定义。
“设计模式是用于解决经常出现的设计问题 [Smalltalk Companion][1]”
“设计模式包含一套描述如何完成某些任务的规则[Pree,1994]”
“设计模式更专注于重用经常性设计的主题,而框架关注细节设计和实现[Coplien and Schmidt,1995]”
“设计模式对付在特定情况出现的设计问题和提出解决方法[Buschmann and Meunier, et al., 1996]”
“设计模式指定单类级或组件级抽象[Gamma,Helm,Johnson, and Vlissides, 1993]”
模式是一种指导,在一个良好的指导下,有助于你完成任务,有助于你作出一个优良的设计方案,达到事半功倍的效果。而且会得到解决问题的最佳办法。
按 4人组的《设计模式》可以把设计模式分成创建型(Creational Patterns),结构型(Structural Patterns),行为型(Behavioral Patterns)3类,一共23种[2]。创建型模式为你创建对象,而不必由你直接实例化对象,包括抽象工厂模式(Abstract Factory),创建者模式(Builder),工厂方法模式(Factory Method),原型模式(Prototype),单例模式(Singleton),结构型模式有助于将对象组合成更大的结构,包括适配器模式(Adapter),桥接模式(Bridge),组合模式(Composite),装饰者模式(Decorator),外观模式(Facade),享元模式(Flyweight),代理模式(Proxy),行为型模式有助于定义系统中对象之间的通信,以及在一个复杂的程序中如何控制流程,包括责任链模式(Chain of Responsibility),命令模式(Command),解释器模式(Interpreter),迭代器模式(Iterator),中介者模式(Mediator),备忘录模式(Memento),观察者模式(Observer),状态模式(State),策略模式(Strategy),模板方法模式(Template Method),访问者模式(Visitor)。
如果能够有效地利用设计模式,采用灵活多变的,方式进行编程,就可以极大地提高程序代码的可重用性和可维护性。
设计模式最重要是分清每种模式的应用场景,而不是硬套它的类结构或代码。有些模式的类结构是基本上相似的,但应用场景和解决的问题不一样。
《设计模式》书中的23种模式都有若干个著名的应用,这些应用具有一定的通用性,可以方便地应用于不同应用领域,并且包含多个对象。设计模式是一种显而易见的工具,通过阅读模式的小结可以理解的基本运用。
本文主要涉及工厂方法和相关的模式与应用。
2 工厂模式
工厂模式系中有3种不同的模式,分别是简单工厂模式(又名静态工厂方法),工厂方法模式以及抽象工厂模式。其中工厂方法和抽象工厂模式是四人组《设计模式》中的两个不同的模式,而简单工厂模式是它们的简化特例[3]。
2.1 简单工厂模式
工厂模式是我们在面向对象编程中经常看见的模式。工厂模式是通过传递参数从一组可能的类中其中一个产生实例。通常它返回的类都具有共同的父类和共同的方法,但是每个类执行的任务不同。
工厂方法模式中的一个特例是简单工厂模式,它是工厂方法模式和抽象工厂方法的简化。简单工厂模式由3个角色组成:简单工厂类,它是简单工厂的核心部分,包含一些必要的判断。抽象产品类,它是具体产品类的抽象父类或简单工厂的访问接口。具体产品类,它们的实例是简单工厂创建的,如图1所示。
图1 简单工厂模式
简单工厂模式实现起来简单,并且能使客户端不用直接生成产品,从创建产品的责任中解脱出来,而对产品类部分而言,可以对抽象产品进扩充而不用对以前的抽象类和具体类进行修改,符合了开闭原则(对扩展开放、对修改关闭)[4]。
简单工厂模式的缺点,简单工厂类负责了创建产品的逻辑,当对产品进行扩充时,需要对简单工厂类进行修改,重新编译程序。如果这个类不能完成工作的话,整个程序都会受到影响。
2.2 工厂方法模式
根据上述,我们可以对简单工厂模式进行改进,对工厂类进行抽象,形成了工厂方法模式。工厂方法模式是一种更灵活的模式,它扩展了子类实例化的思想,即不再由单个工厂类决定到底应该实例化哪个子类。而将这一决定推迟到每个子类中完成。这种模式编写的程序定义了一个抽象类或接口,虽然它负责创建对象(定义了创建的方法),但是应该创建哪个对象将由子类来决定。
当一个类不知道它所须创建的对象类的时候,或者当一个类希望由它的子类来指定它所创建的对象的时候,或者当类将创建对象的职责委托给多个帮助子类中某个的时候可以使工厂方法模式,它对比简单工厂把工厂类分成了具体工厂和抽象工厂,工厂方法不再将与选定应用有关的类绑定。增加一个具体产品时,不必对抽象工厂或工厂接口进行修改,如图2所示。
工厂方法模式是设计模式中应用非常广泛。与简单工厂模式相比,工厂方法模式核心是抽象工厂类或者工厂接口,很好的符合了开闭原则。
图2 工厂方法模式
2.3 抽象工厂模式
当我们增加一个产品时,我们需要在程序中增加一个产品类并增加一个相应的产品工厂类,而当我需要增加一类产品时,我们需要运用别一种工厂模式,抽象工厂模式。
抽象工厂模式是比工厂方法模式更抽象的一种模式。使用这种模式可以返回多个相关对象类中的一个。
抽象工厂模式的角色和工厂方法的角色相似,不同的是抽象工厂中的可以根据不同的产品类型产生不同类的产品。多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。一个抽象工厂类,可以派生出多个具体工厂类。每个具体工厂类可以创建多个具体产品类的实例。
当一个系统要独立于它的产品的创建,组合和表示时,或者要由多个产品系统列中的一个来配置时,或者当你要强调系统相关的产品对象的设计时可以运用抽象工厂方法。
图3 抽象工厂模式
抽象工厂模式和工厂方法模式一样,将客户与类的实现分离,客户通过它们的抽象接口操纵实例,客户不必关心具体类的生成,实现了高内聚,低耦合。和工厂方法模式不同的是,它使得易于交换产品系。一个应用只需要在初始化的时候确定,只具体工厂就可以设置不同的产品系统,如图3所示。
抽象工厂模式的缺点是增加具体类比较困难,抽象工厂或工厂接口已经确定了可以产生的产品系列,如何要扩展也需要扩展应抽象类及其子类。
2.4 反射机制与工厂模式
Java反射机制[5],反射用于Java身上指的是我们可以于运行时加载,探知,使用编译期间完全未知的类。反射可以用于工厂模式中改进工厂模式。在简单工厂模式中,如果增加不同的产品需要在修改工厂的逻辑,如果利用 Java中的反射机制,就可以动态地选择要实例化的类的,无需要对工厂类进行重新编译,增加产品只需要继承抽象产品的接口。同样,在工厂方法创建实例中,也可以运用反射机制使具体工厂对象和客户端之间降低耦合。
3 工厂模式的应用
Java基础的类库中用到很多四人组的设计模式,设计模式并不是类库函数,它是比类库函数更具有一般性的抽象。类库函数是用来当组件的程序,而设计模式则是要如何构建组件的思想[6]。
在Java类库中的抽象类DataFormat是简单工厂方法的一个例子。模式中抽象产品和具体工厂的两个角色都由抽象类DataFormat担当。具体产品角色则是SimpleDateFormat,如图4所示。
图4 DataFormat类
例子中GetDateInstance则是一个表态工厂方法。
Java类库中经常用到的Immtable(不变)类型,如Integer类,其它一个valueOf方法是一个静态工厂方法,创建Integer对象,它可以提高Integer对象的可重用性。还有util包中用于本地化的 ResourceBundle类同样也提供了创建它的子类的静态工厂方法。
Java集合的接口用有运用到工厂方法模式来创建相应的迭代器,在这个例子中,迭代器部分是抽象产品类和具体产品类,集合部分则是工厂接口和具体工厂,如图5所示。
4 工厂模式和其它模式的关系
各种模式关系除了可按上述分成创建型,结构型,行为型三类。于类还是用于对象,可将其分为类模式和对象模式。类模式处理类和子类之间的关系,这些关系通过继承建立,是静态的,在编译时便确定下来了;对象模式处理对象间的关系,这些关系在运行时是可以变化的,更具动态性[7]。
图5 迭代器实例
设计模式存在着紧密或相对差别比较大的关系。通过学习,比较,联想,我们可以更好的理解,掌握和运用各种模式。
单例模式了中的静态方法是静态工厂方法,单例模式可以算是一种表态工厂模式,单例类自己是工厂角色,也是产品角色。
工厂方法模式是模板方法的一种应用,上述中工厂方法模式中工厂部分中的CreateProduct就是模板方法。
工厂访求模式中的角色具体工厂可以用单例模式实现。在 java类库中,很多工厂模式都结合应用了单例模式。工厂方法模式中的具体产品角色有时可以用组件模式实现。还有如上述Java类库中的迭代器例子。在迭代器产生实例时,可以用到工厂方法模式。
同工厂方法模式一样,具体工厂可以用单例模式实现,具体产品也可以用组件模式实现。
5 结束语
设计模式已经成为面向对象设计的重要内容,设计模式也为面向对象编程做出重要指导,很大程序地提高了可重用性和可理解性。本文只是对其中的工厂方法作为了一些总结。在四人组中还有其它的设计模式同类是经过反复运用,从经验中总结出来的,通过设计模式的理解,体会,我们也可以在今后的从更高更透彻地认识面向对象编程的精髓。
[1]James W Cooper. Java™ Design Patterns: A Tutorial,Addison-Wesley.2000.
[2]Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns. Addison-Wesley.1995.
[3]阎宏. Java与模式[M].电子工业出版社. 2002,10.
[4]Robert C Martin, 邓辉译. Agile Software Development:Principles, Patterns, and Practices[M].清华大学出版社.2003,9.
[5]侯捷. Java 反射机制.程序员. 2004,10.
[6]结城浩著,博硕文化译.设计模式-Java 语言中的应用,中国铁道出版社.
[7]计春雷.软件设计模式及其应用研究[J].上海电机学院学报,2006,10,9.