1.意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类实例化延迟到其子类。
2.别名
虚拟构造器(Virtual Constructor)
3.动机
框架使用抽象类定义和维护对象之间的关系。这些对象的创建通常也由框架负责。
考虑这样一个应用框架,它可以向用户显示多个文档。在这个框架中年,两个主要的抽象类Application和Document。这两个类都是抽象的,客户必须通过他们的子类来做与具体应用相关的实现。因为被实例化的特定Document子类时与特定应用相关的,所有Application类不可能预测到哪个Document子类将被实例化--Application类仅知道一个新的文档何时应被创建,而不知道哪一种Document将被创建。这就产生了一个尴尬的局面:框架必须实例化类,但是它只知道不能被实例化的抽象类。
Factory Method 模式提供了一个解决方案。它封装了哪一个Document子类将被创建的信息,并将这些信息从该框架中分离出来。Application的子类重定义Application的抽象操作CreateDocument以返回适当的Document子类对象。一旦一个Applciation子类实例化以后,它就可以实例化与应用相关的文档,而无需知道这些文档的类。我们称CreateDocument是一个工厂方法(factory method),因为它负责“生成一个对象”。
4.适用性
- 当一个类不知道它所必须创建的对象的类的时候
- 当一个类不知道它的子类来指定它所创建的对象的时候
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类时代理者这一信息局部化的时候。
5.结构
6.参与者
- Product(Document)定义工厂方法创的对象的接口
- ConcreteProduct(MyDocument)实现Product接口
- Creator(Application)声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个功放方法的缺省实现,它返回一个缺省的ConcreteProduct对象。可以调用工厂方法以创建一个Product对象
- ConcreteCreator(MyApplication)重新定义工厂方法以返回ConcreteProduct实例
7.协作 Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的ConcreteProduct实例。
8.效果
- 为子类提供挂钩(hook) 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。Factory Method 给子类一个挂钩以提供对象的扩展版本。
- 连接平行的类层次 当一个类将它的一些职责委托给一个独立的类的时候,就产生了平行类层次。考虑可以被交互操作的图形,也就是说,他们可以用鼠标进行伸展、移动,或旋转。实现这样一些交互并不是总是那么容易,它通常需要春城和恭喜在给定时刻基类操作状态的邢,这个状态仅仅在操纵是需要。因此它不需要被保存在图形对象中。此外,当用户操作图形时,不同的图形有不同的行为。
9.实现(需要注意的问题)
- 主要有两种不同的情况 Factory Method模式主要有两种不同的情况:(1)Creator类是一个抽象类并且不提供它所声明的工厂方法的实现,这种情况下学院子类来实现,因为没有合理的缺省实现。它避免了不得不实例化不可预见类的问题。(2)Creator是一个具体的类而且为工厂方法提供一个缺省的实现。具体的Creator主要是因为灵活性才使用工厂方法。它所遵循的准则是,“用一个独立的操作创建对象,这样子类才能重定义他们的创建方式”。这条准则保证了子类的设计者能够在必要的时候改变父类所实例化的对象的类。
- 参数化工厂方法 该模式的另一种情况使得工厂方法可以创建多种产品。工厂方法采用一个表示要被创建的对象种类的参数。工厂方法创建的所有对象将共享Product接口。在Document的例子中,Appliction可能支持不同种类的Document。你给CreateDocument传递一个外部参数来指定要创建的文档的种类。
- 特定语言的变化和问题 不同的语言有助于产生其他一些有趣的变化和警告。
- 使用模板以避免创建子类 正如我们已经提及的,工厂方法另一个潜在的问题是他们可能仅为了创建适当的Product对象而迫使你创建Creator子类。我们可以提供Creator的一个模板子类,它使用Product类作为模板参数。
10.代码实例
函数CreateMaze创建并返回一个迷宫。这个函数存在的一个问题时它对迷宫、房间、门和墙壁的类进行了硬编码。我们将引入工厂方法以使子类可以选择这些构想。完整代码在后面的代码下载中。
11.已知应用
工厂方法主要用于工具包和框架中。
12.相关模式
Abstract Factory经常用工厂方法来实现。