工厂方法(Factory Method)模式: 定义一个创建产品对象的工厂接口,但让其子类决定实例化哪一个类。使一个类的实例化延迟到其子类。
核心精神是封装类中不变的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。
核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。
在下列情况下可以使用Factory Method模式:
• 当一个类不知道它所必须创建的对象的类的时候。
• 当一个类希望由它的子类来指定它所创建的对象的时候。
• 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
核心结构有四个角色:
抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的Concrete Product对象。
可以调用工厂方法以创建一个Product对象。
具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。
实现定义在抽象工厂中的工厂方法以返回一个Concrete Product实例。
抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。 定义工厂方法所创建的对象的接口。
具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
协作
• Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的Concrete Product实例。
效果
工厂方法不再将与特定应用有关的类绑定到你的代码中。代码仅处理Product接口;因此它可以与用户定义的任何Concrete Product类一起使用。
工厂方法的一个潜在缺点在于客户可能仅仅为了创建一个特定的Concrete Product对象,就不得不创建Creator的子类。当Creator子类不必需时,客户现在必然要处理类演化的其他方面;但是当客户无论如何必须创建Creator的子类时,创建子类也是可行的。
为子类提供挂钩(hook):用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。Factory Method()给子类一个挂钩以提供对象的扩展版本(即一个Creator可以有多个ConcreteCreate类,由hook决定使用哪个)。
连接平行的类层次:当一个类将它的一些职责委托给一个独立的类的时候,就产生了平行类层次。使用一个独立的Manipulator对象实现交互并保存所需要的任何与特定操纵相关的状态。不同的图形将使用不同的Manipulator子类来处理特定的交互。得到的Manipulator类层次与Figure类层次是平行(至少部分平行),如下图所示。
Figure类提供了一个CreateManipulator工厂方法,它使得客户可以创建一个与Figure相对应的Manipulator。Figure子类重定义该方法以返回一个合适的Manipulator子类实例。做为一种选择,Figure类可以实现CreateManipulator以返回一个默认的Manipulator实例,而Figure子类可以只是继承这个缺省实现。这样的Figure类不需要相应的Manipulator子类—因此该层次只是部分平行的。
实 现
Factory Method模式主要有两种不同的情况:
1)第一种情况是,Creator类是一个抽象类并且不提供它所声明的工厂方法的实现。需要子类来定义实现,因为没有合理的缺省实现。它避免了不得不实例化不可预见类的问题。
参数化工厂方法:使得工厂方法可以创建多种产品。工厂方法采用一个标识要被创建的对象种类的参数。工厂方法创建的所有对象将共享Product接口。
2)第二种情况是,Creator是一个具体的类而且为工厂方法提供一个缺省的实现。也有可能有一个定义了缺省实现的抽象类,但这不太常见。具体的Creator主要因为灵活性才使用工厂方法。它所遵循的准则是, “用一个独立的操作创建对象,这样子类才能重定义它们的创建方式。 ”这条准则保证了子类的设计者能够在必要的时候改变父类所实例化的对象的类。
Abstract Factory(3.1)经常用工厂方法来实现。
工厂方法通常在Template Methods(5 .10)中被调用。
Prototypes(3.4)不需要创建Creator的子类。但是,它们通常要求一个针对Product类的Initialize操作。Creator使用Initialize来初始化对象。而Factory Method不需要这样的操作。
简单工厂模式跟工厂方法模式区别是:简单工厂只有三个要素,他没有工厂接口,并且得到产品的方法一般是静态的。