设计模式—简单工厂模式中提到了该模式的几点弊端:

  1. 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
  2. 违背“开闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂;
  3. 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构

为了解决这些弊端,出现了工厂方法模式。

工厂方法模式(Factory Method Pattern),其定义如下: :::info Define an interface for creating an object,but let subclasses decide whichclass to instantiate.Factory Method lets a class defer instantiation tosubclasses.

定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。 :::

  1. 存在工厂的抽象基类,规定创建产品的原则与规则;
  2. 每个工厂实现类创建不同的产品,符合开闭原则,也可以合适地利用继承等语言特性。

也就是说,工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象

其组成模型如下:

组成 关系 作用
抽象产品(Product) 具体产品的父类 提供描述产品的公共接口
具体产品(Concrete Product) 具体产品类,工厂生产的目标类 抽象产品具体化
抽象工厂(Factory) 具体工厂的父类 描述具体工厂的公共接口
具体工厂(Concrete Factory) 抽象工厂的子类;被外界调用 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例


工厂方法模式的优点

  1. 封装性良好,代码结构清晰,符合单一职责原则;
  2. 良好的扩展性,符合开闭原则

工厂方法的缺点

  1. 增加新产品,必随着增加新工厂。类个数成对增加,增加系统复杂性;
  2. 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度;
  3. 一个具体工厂只能创建一种具体产品

工厂方法模式最佳实践

  1. 当一个类不知道它所需要的对象的类时;在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可;
  2. 当一个类希望通过其子类来指定创建对象时;在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展;
  3. 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中;

工厂方法模式实现步骤

  1. 创建抽象产品,定义产品的公共能力;
  2. 创建具体产品类,实现自己的独有能力;
  3. 创建抽象工厂,定义生产的公共能力;
  4. 创建具体工厂类,实现自己的生成能力,具体到能生产哪种产品;
  5. 外界调用具体工厂生成具体产品。

工厂方法模式使用示例

使用工厂方法模式生产不同的Pencil。

  1. public class FactoryMethod {
  2. /**
  3. * 抽象产品类,并定义具体产品的基本功能
  4. */
  5. public interface IPencil {
  6. void write();
  7. }
  8. /**
  9. * 具体产品类:钢笔
  10. */
  11. public static class Fountain implements IPencil {
  12. @Override
  13. public void write() {
  14. System.out.println("使用钢笔写字");
  15. }
  16. }
  17. /**
  18. * 具体产品类:铅笔
  19. */
  20. public static class Pencil implements IPencil {
  21. @Override
  22. public void write() {
  23. System.out.println("使用铅笔写字");
  24. }
  25. }
  26. /**
  27. * 工厂抽象,提供生产产品的方法
  28. */
  29. public interface IFactory {
  30. IPencil createPencil();
  31. }
  32. /**
  33. * 钢笔类工厂
  34. */
  35. public static class FountainFactory implements IFactory {
  36. @Override
  37. public IPencil createPencil() {
  38. return new Fountain();
  39. }
  40. }
  41. /**
  42. * 铅笔类工厂
  43. */
  44. public static class PencilFactory implements IFactory {
  45. @Override
  46. public IPencil createPencil() {
  47. return new Pencil();
  48. }
  49. }
  50. public static void main(String[] args) {
  51. // 生产铅笔
  52. new PencilFactory().createPencil().write();
  53. // 生产钢笔
  54. new FountainFactory().createPencil().write();
  55. }
  56. }

输出结果:
** :::success 使用铅笔写字
使用钢笔写字 :::