FACTORY METHOD(工厂方法) ---- 对象创建型模式

1、意图
    定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到子类。
2、别名
    虚拟构造(Virtual Constructor)
3、动机
    框架使用抽象类定义和维护对象之间的关系。这些对象的创建通常也由框架负责。
    考虑这样一个框架,它可以向用户展示多个文档。在这个框架中,两个主要的抽象是类Application和Document。这两个类都是抽象的,客户必须通过它们的子类来做与具体应用相关的实现。例如,为创建一个绘图应用,我们定义DrawingApplication和DrawingDocument。Application类负责管理Document并根据需要创建它们----例如,当用户从菜单中选择Open或New的时候。
    因为被实例化的特定Document子类是与特定应用相关的,所以Application类不可能预测到哪个Document子类将被实例化----Application类仅知道一个新的文档何时被创建,而不知道哪一个Document将被创建。这就产生了一个尴尬的局面:框架必须实例化类,但是它只知道不能被实例化的抽象类。
    Factory Method模式提供了一个解决方案。它封装了哪一个Document子类将被创建的信息并将这些信息从该框架中分离出来。如下图所示

FACTORY METHOD(工厂方法) ---- 对象创建型模式_第1张图片

    Application的子类重定义Application的抽象操作CreateDocument以返回适当的Document子类对象。一旦一个Application子类实例化以后,它就可以实例化与应用相关的文档,而无需知道这些文档的类。我们称CreateDocument是一个工厂方法(factory method),因为它负责“生产”一个对象。
4、适用性
    在下列情况下可以使用Factory Method模式:
    当一个类不知道它所创建的对象的类的时候。
    当一个类希望由它的子类来指定它所创建的对象的时候。
    当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
5、结构

FACTORY METHOD(工厂方法) ---- 对象创建型模式_第2张图片
6.参与者
    Product(Document)
----定义工厂方法所创建的对象的接口
    ConcreteProduct
----实现Product接口
    Creator(Application)
----声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的ConcreteProduct。
----可以调用工厂方法创建一个Product对象
    ConcreteProduct(MyApplication)
----重定义工厂方法以返回一个ConcreteProduct实例。
7、协作
    Creator依赖于它的子类来定义工厂方法,所以它返回一个适当的ConcreteProduct实例。
8、效果
    工厂方法不再将与特定应用有关的类绑定到你的代码中。代码仅处理Product接口;因此它可以与用户定义的任何ConcreteProduct类一起使用。
    工厂方法的一个潜在缺点在于客户可能仅仅为了创建一个特定的ConcreteProduct对象,就不得不创建Creator的子类。当Creator子类不必需时,客户现在必然要处理类演化的其他方面;但是当客户无论如何必须创建Creator的子类时,创建子类也是可行的。
    下面是Factory Method模式的另外两种效果:
     1)为子类提供挂钩(hook) 用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。Factory Method给子类一个挂钩以提供对象的扩展版本。
     在Document的例子中,Document类可以定义一个称为CreateFileDialog的工厂方法,该方法为打开一个已有的文档创建默认的文档对话框对象。Document的子类可以重新定义这个工厂方法以定义一个与特定应用相关的文件对话框。在这种情况下,工厂方法就不再抽象了而是提供了一个合理的缺省实现。
     2)连接平行的类层次  迄今为止,我们所考虑的例子中,工厂方法并不往往只是被Creator调用,客户可以找到一些有用的工厂方法,尤其在平行类层次的情况下。
     当一个类将它的一部分职责委托给一个独立类的时候,就产生了平行类层次。考虑可以被交互操纵的图形;也就是说,它们可以用鼠标进行伸展、移动,或者旋转。实现这样一些交互并不总是那么容易,它通常需要存储和更新在给定时刻记录操纵状态的信息,这个状态仅仅在操纵时需要。因此它不需要被保存在图形对象中。此外,当用户操纵图形时,不同的图形有不同的行为。例如,将直线图形拉长可能会产生一个端点被移动的效果,而伸展正文图形则有可能改变行距。
    有了这些限制,最好使用一个独立的Manipulator对象实现交互并保存所需要的任何与特定操纵相关的状态。不同的图形将使用不同的Manipulator子类来处理特定的交互。得到的Manipulator类层次与Figure类层次是平行(至少部分平行),如下图所示。

FACTORY METHOD(工厂方法) ---- 对象创建型模式_第3张图片
    Figure类提供了一个CreateManipulator工厂方法,它使得客户可以创建一个与Figure相对应的Manipulator。Figure子类重定义该方法以返回一个合适的Manipulator子类实例。作为一种选择,Figure类可以实现CreateManipulator以返回一个默认的Manipulator实例,而Figure子类可以继承这个缺省的实现。这样的Figure类不需要相应的Manipulator子类----因此该层次只是部分平行的。
9、代码示例
    A maze game may be played in two modes, one with regular rooms that are only connected with adjacent rooms, and one with magic rooms that allow players to be transported at random,The regular game mode could use this template method:

public class MazeGame {
  public MazeGame() {
     Room room1 = makeRoom();
     Room room2 = makeRoom();
     room1.connect(room2);
     this.addRoom(room1);
     this.addRoom(room2);
  }
 
  protected Room makeRoom() {
     return new OrdinaryRoom();
  }
}

    In the above snippet, the MazeGame constructor is a template method that makes some common logic. It refers to the makeRoom factory method that encapsulates the creation of rooms such that other rooms can be used in a subclass. To implement the other game mode that has magic rooms, it suffices to override the makeRoom method:
public class MagicMazeGame extends MazeGame {
  @Override
  protected Room makeRoom() {
      return new MagicRoom();
  }
}

10、相关模式
    Abstract Factory经常用工厂方法来实现。
    工厂方法通常在Template Method中被调用。在上面代买示例中MazeGame就是一个模板方法,在文档例子中,NewDocument也是一个模板方法。
    Prototype不需要创建Creator的子类。但是,它们通常要求一个针对Product类的Initialize操作。Creator使用Initialize来初始化对象。而Factory Method不需要这样的操作。

你可能感兴趣的:(factory)