本文首发于 http://www.YoungZY.com/
意图
- 定义一个用来创建对象的接口,由其子类(实现类)决定哪个类应该被初始化。工厂方法把类的初始化过程延迟到子类里
- 定义一个虚拟的构造器
new
是危险的操作
问题
一个框架需要对其架构模型有一套标准化的操作规范,但对一个单独的应用来说,可以定义不同的作用域对象及其初始化过程。
讨论
工厂方法模式是为了创建对象,就像模板方法模式是为了实现一种算法。接口定义了标准的创建对象的方法(用纯虚拟的标识——如abstract——来修饰创建步骤),然后委托子类去完成创建的具体步骤,并将子类提供给客户端调用。
工厂方法模式使得设计具有更多的可定制化空间,而只是多了一点点复杂性。其他设计模式需要新的类,而它只需要新的操作(方法)。
大家经常使用工厂方法模式作为创建对象的标准方式,但以下情况就没有必要用了:初始化过程不会再改变的类,或者初始化过程被放在很容易被子类覆盖的方法里(如构造函数)。
工厂模式方法和抽象工厂很相似,只是少了那一组相关或类似对象。
工厂模式通常是在基础框架中定义,然后由使用者去实现。
结构
在“四人帮设计模式中”,工厂方法模式和抽象工厂模式有很多重复的地方(见下图)。鉴于此,本文阐述的是当下最流行的实现。
现在越来越流行的抽象工厂的实现方式是:定义一个 static
方法返回对象实例。与构造函数不同的是:1)实际返回的可能是某个子类的实例;2)已经存在的实例可能被重复使用,而不是创建一个新的实例;3)工厂方法模式可以有更高辨识度的名字,如 Color.makeRGBColor(float r, float g, float b)
或者Color.makeHSBColor(float h, float s, float b)
。
客户端与衍生的子类完全解耦。多态地创建实例变为可能。
举例
注模机印证了这种模式。塑料玩具的制造厂商先处理塑料制模粉,然后将其注入指定形状的模具中。玩具类(小汽车、玩偶等)是由模具决定的。
核查清单(也可以理解为应用步骤)
- 如果有一套运用多态的继承关系,考虑在基类里定义一个静态的工厂方法,来增加动态创建多态实例的能力。
- 给工厂方法定义入参,使其能够清楚地知道具体哪个衍生类应该被实例化。
- 考虑设计一个“对象池”,使对象的实例可以重复使用而不是简单的创建
- 考虑将所有的构造函数改为
private
或protected
修饰
经验法则
- 工厂方法的优势在于它可以多次返回同一个实例,或者返回一个子类而不是某个特定的类型。
- 作为编程语言的设计或风格,有些工厂模式决绝地建议将所有类的构造函数定义为
private
或protected
。一个类大量地创建新对象还是重复地使用老对象,都行,自己决定就好,跟别人无关。 new
操作被认为是有害的。请求一个对象和创建一个对象之间是由区别的。new
通常是创建一个对象,且没有封装对象的创建。工厂方法强制封装,并且允许请求一个对象而不需要与创建行为产生不可解的耦合。
(译者注:详细的代码实例请移步 GitHub )
加入讨论