定义

定义一个创建对象的接口、让子类决定实例化哪一个类, Factory Method 使一个类的实例化延迟到其子类。

结构和说明

创建型模式-工厂方法模式 - 图1

示例代码

  1. public class FactoryMethodDemo {
  2. public static interface Product {
  3. }
  4. public static abstract class Creator {
  5. protected abstract Product factoryMethod();
  6. public void somOperation() {
  7. // 通常在这些方法实现中需要调用工厂方法来获取 Product 对象
  8. Product product = factoryMethod();
  9. }
  10. }
  11. public static class ConcreteProduct implements Product {
  12. }
  13. public static class ConcreteCreator extends Creator {
  14. @Override
  15. protected Product factoryMethod() {
  16. return new ConcreteProduct();
  17. }
  18. }
  19. }

这里要注意一个问题,子类在实现这些抽象方法的时候,通常并不是真正地由子类来实现具体的功能,而是在子类的方法里面做选择,选择具体的产品实现对象。

父类里面,通常会有使用这些产品对象来实现一定的功能的方法,而且这些方法所实现的功能通常都是公共的功能,不管子类选择了何种具体的产品实现,这些方法的功能总是能正确执行。

模式讲解

  • 谁来使用工厂方法创建的对象

是 Creator 中的其他方法在使用工厂方法创建的对象,虽然也可以把工厂方法创建的对象直接提供给 Creator 外部使用,但工厂方法模式的本意可,是由 Creator 对象内部的方法来使用工厂方法创建的对象,也就是说,工厂方法一般不提供给 Creator 外部使用。
客户端应该使用 Creator 对象,或者使用由 Creator 创建出来的对象。对于客户端使用 Creator 对象,这个时候工厂方法创建出来的对象,这个时候工厂方法创建出来的对象,是 Creator 中某些方法使用;对于使用那些由 Creator 创建出来的对象,这个时候工厂方法创建的对象,是构成客户端需要的对象的一部分。分别举例说明。

(1) 客户端使用 Creator 对象的情况

  1. /**
  2. * 客户端使用 Creator 对象的情况下, Creator 的基本实现
  3. */
  4. public abstract class Creator1 {
  5. /**
  6. * 工厂方法,一般不对外
  7. *
  8. * @return 创建的产品对象
  9. */
  10. protected abstract Product factoryMethod();
  11. public void someOperation() {
  12. // 在这里使用工厂方法
  13. Product product = factoryMethod();
  14. }
  15. }

(2) 客户端使用 Creator 创建出来的对象

  1. /**
  2. * 客户端使用 Creator 来创建客户单需要的对象的情况下, Creator 的基本实现
  3. */
  4. public abstract class Creator2 {
  5. /**
  6. * 工厂方法,一般不对外,创建一个部件对象
  7. *
  8. * @return 创建的产品对象,一般是另一个产品对象的部件
  9. */
  10. protected abstract Product1 factoryMethod1();
  11. /**
  12. * 工厂方法,一般不对外,创建一个部件对象
  13. *
  14. * @return 创建的产品对象,一般是另一个产品对象的部件
  15. */
  16. protected abstract Product2 factoryMethod2();
  17. public Product createProduct() {
  18. // 在这里使用工厂方法, 得到客户端所需对象的部件对象
  19. Product1 p1 = factoryMethod1();
  20. Product2 p2 = factoryMethod2();
  21. // 工厂方法创建的对象是创建客户端对象所需要的
  22. Product p = new ConcreteProduct();
  23. p.setProduct1(p1);
  24. p.setProduct2(p2);
  25. return p;
  26. }
  27. }

小结一下: 在工厂方法模式里面,客户端要么使用 Creator 对象,要么使用 Creator 创建的对象,一般客户端不直接使用工厂方法。当然也可以直接把工厂方法暴露给客户端操作,但是一般不这么做。

调用顺序

客户端使用 Creator 对象的情况

创建型模式-工厂方法模式 - 图2

客户端使用 Creator 创建出来的对象

创建型模式-工厂方法模式 - 图3

参数化工厂

  1. /**
  2. * 1. 非抽象
  3. */
  4. public static class Creator {
  5. /**
  6. * 2. 非抽象, 有默认实现
  7. *
  8. * @param type
  9. * @return
  10. */
  11. protected Product factoryMethod(int type) {
  12. // 根据参数来选择 Product 实现
  13. return null;
  14. }
  15. public void someOperatioin(int type) {
  16. Product product = factoryMethod(type);
  17. }
  18. }

优缺点

优点

  • 可以在不知具体实现的情况下编程

工厂方法模式可以让你在实现功能的时候,如果需要某个产品对象,只需要使用产品的接口即可,而无须关心具体的实现。选择具体实现的任务延迟到子类去完成。

  • 更容易扩展对象的新版本

工厂方法给子类提供了一个挂钩,使得扩展新对象的版本非常容易。

另外这里提到的挂钩,就是我们常说的钩子方法(hook)

  • 链接平行的类层次

工厂方法出了创造产品对象外,在链接平行的类层次上也大显身手。

缺点

  • 具体产品对象和工厂方法的耦合性

在工厂方法模式中,工厂方法是需要创建产品对象的,也是需要选择具体的产品对象,并创建他们的实例,因此具体产品对象和工厂方法是耦合的。

思考

本质

延迟到子类来选择实现

对设计原则的体现

  • 依赖倒置原则

何时选用

  • 如果一个类需要创建某个接口的对象,但是又不知道具体的实现,这种情况可以选用工厂方法模式,把创建对象的工作延迟到子类中去实现。
  • 如果一个类本身就希望由它的子类来创建所需的对象的时候,应该使用工厂方法模式。

相关模式

  • 工厂方法模式和抽象工厂模式

这两个模式可以组合使用,具体的放到抽象工厂模式中去讲。

  • 工厂方法模式和模版方法模式

这个模式外观类似,都有一个抽象类,然后由子类去提供一些实现,但是工厂方法模式的子类专注的是创建产品对象,而模版方法的子类专注的是为固定的算法骨架提供某些步骤的实现。
这两个模式可以组合使用,通常在模版方法里面,使用工厂方法来创建模版方法需要的对象。