工厂方法模式是什么?

工厂方法模式(Factory Method Pattern)是一种创建型的设计模式,它的指导思想是在父类提供一个用于创建产品的接口,但让子类来决定创建何种具体的产品。

UML 类图

用 UML 类图来描述工厂方法模式的结构,在模式中各个角色之间的关系:
image.png
根据上图,总结了模式中各个角色的职责以及它们之间的关系:

  • 产品抽象出一组接口,对于创建者及其子类构建的对象而言,这些接口都是通用的。
  • 具体产品是对产品接口的不同实现。
  • 创建者会声明返回产品对象的工厂方法,而方法返回的对象类型必须与产品接口相匹配。需要了解的是,尽管它的名字是创建者,但它最主要的职责并不一定就是创建产品。一般来说,创建者类会包含一些与产品相关的业务逻辑,工厂方法帮助我们将这些逻辑与具体的产品类解耦。
  • 具体创建者重写基础的工厂方法,使其返回不同类型的产品。需要注意的是,每次调用工厂方法时并不一定都要创建新的实例。工厂方法也可以返回缓存、对象池或其他来源的已有对象。

案例

让我们通过一个案例来帮助我们理解工厂方法模式。假设有如下情景:在各大笔记本专卖店中,有笔记本产品展示以供售卖。在苹果商店展示的是 Mac Book,在微软商城展示的是 Surface 等等。
借助上述的模式结构,我们先梳理一下情景中的各个角色。首先,产品这一角色是笔记本,它是对各种类型的笔记本的抽象。

  1. public interface Laptop {
  2. void startup();
  3. void work();
  4. void shutdown();
  5. // other methods
  6. }

而 MacBook、Surface 是具体的产品。

  1. public class MacBook implements Laptop {
  2. @Override
  3. public void startup() {
  4. System.out.println("Starting up the MacBook.");
  5. }
  6. @Override
  7. public void work() {
  8. System.out.println("The MacBook is working.");
  9. }
  10. @Override
  11. public void shutdown() {
  12. System.out.println("Shutting down the MacBook.");
  13. }
  14. // other methods
  15. }
  16. public class Surface implements Laptop {
  17. // ...
  18. }

创造者这一角色是笔记本专卖店,它声明了一个接口用来创建笔记本,而究竟创建何种类型的笔记本,则由具体的专卖店来控制。

  1. public abstract class LaptopStore {
  2. public abstract Laptop createLaptop();
  3. public void display(Laptop laptop) {
  4. laptop.startup();
  5. laptop.work();
  6. }
  7. // other business logic
  8. }

而苹果商店和微软商城等则是具体的创建者。

  1. public class AppleStore extends LaptopStore {
  2. @Override
  3. public Laptop createLaptop() {
  4. return new MacBook();
  5. }
  6. }
  7. public class MicrosoftStore extends LaptopStore {
  8. @Override
  9. public Laptop createLaptop() {
  10. return new Surface();
  11. }
  12. }

最后,我们通过一个用例来模拟一下上述的情景:

  1. public class FactoryMethodMain {
  2. public static void main(String[] args) {
  3. String storeType = args != null && args.length > 0 ? args[0] : null;
  4. LaptopStore laptopStore;
  5. if ("Apple".equalsIgnoreCase(storeType)) {
  6. laptopStore = new AppleStore();
  7. } else if ("Microsoft".equalsIgnoreCase(storeType)) {
  8. laptopStore = new MicrosoftStore();
  9. } else {
  10. throw new IllegalArgumentException("Unknown Laptop Store.");
  11. }
  12. Laptop laptop = laptopStore.createLaptop();
  13. laptopStore.display(laptop);
  14. }
  15. }

案例源码

可在 GitHub 上查看上述案例的完整代码。

优点与不足

工厂方法模式具有如下优点:

  • 可以避免创建者与具体产品之间的耦合。
  • 遵循单一职责原则,将创建产品的代码放在程序的单一位置,从而使得代码更容易维护。
  • 遵循开闭原则,无需修改现有的客户端代码,就可以在程序中引入新的产品。

但它也有不足之处:

  • 采用工厂方法模式会引入许多新的子类,代码可能会因此变得更复杂。

参考资料

以下是本文参考的资料: