← 返回题目列表

抽象工厂和工厂方法有什么区别?

高频 中等 第 3 / 25 题 更新于 2026/07/28
抽象工厂模式工厂方法模式产品族创建型模式

简化版

工厂方法通常负责创建一种产品,抽象工厂负责创建一组相关产品。前者解决单条产品线的扩展问题,后者解决多条产品线在同一产品族下的一致创建问题。

详细版

两者的区别可以这样看:

维度工厂方法抽象工厂
创建目标一种产品一组相关产品
抽象接口通常一个创建方法通常多个创建方法
扩展优势新增同类产品新增产品族
典型场景不同 Parser、不同 Sender跨平台 UI、云厂商 SDK 套件

工厂方法例子:

interface ParserFactory {
    Parser createParser();
}

抽象工厂例子:

interface CloudFactory {
    StorageClient createStorage();
    QueueClient createQueue();
}

如果系统只创建一种对象,用工厂方法更轻;如果系统要创建一套互相匹配的对象,用抽象工厂更合适。

完整版教学

一、先看创建对象的数量和关系

如果要创建的对象只有一种,比如报文解析器、消息发送器、日志写入器,重点是这一类产品内部怎么扩展,工厂方法就够用。

如果要创建的是一组对象,并且这些对象必须来自同一套上下文,抽象工厂更合适。

这里的“一组”不是简单指一次创建多个实例,而是多个产品等级之间存在必须共同切换的兼容关系。即使一次创建十个 Parser,它们仍属于同一产品等级,通常还是工厂方法问题。

二、工厂方法是抽象工厂的组成基础

抽象工厂里的每个创建方法都可以看作一个工厂方法。例如 createButton() 创建 Button 产品等级,createCheckbox() 创建 Checkbox 产品等级。

区别在于抽象工厂把多个创建方法放在同一个抽象工厂接口里,用来表达产品族的一致性。

三、扩展方向不同

工厂方法新增产品通常新增一个具体产品和具体工厂。抽象工厂新增产品族通常新增一个具体工厂,并实现所有产品等级的创建方法。

但抽象工厂如果新增产品等级,就会比较麻烦,因为所有具体工厂都要补新方法。

四、不要用复杂度更高的模式解决简单问题

如果系统没有产品族概念,只是创建一种产品,强行使用抽象工厂会让接口显得臃肿。设计模式要跟变化点匹配,而不是越复杂越好。

判断时可以尝试画产品矩阵:只有一列就优先工厂方法,至少两列且每一行必须保持兼容才考虑抽象工厂。这个检查能避免因为接口名称里出现 Factory 就机械升级模式。

五、一列和多列矩阵对应不同模式

工厂方法可看成只关注矩阵的一列:例如 Parser 的多种实现。抽象工厂把 Parser、Validator、Serializer 多列放入同一行工厂,目的不是创建数量更多,而是让同一行的实现保持兼容。

工厂方法:
          Parser
JSON族     JsonParser
XML族      XmlParser
抽象工厂:
          Parser   Validator   Serializer
JSON族     JP       JV          JS
XML族      XP       XV          XS

矩阵的每一行是一族兼容产品,每一列是一个产品等级。客户端选择一行对应的具体工厂,再从该工厂取得各列产品;如果允许调用方绕过工厂分别选择每个具体类,产品族一致性的结构性保证就消失了。

六、二维扩展成本与模式边界

评审维度本题结论
产品族不变量工厂方法维持单个产品抽象;抽象工厂维持一组产品的族一致性。
新增一行(产品族)工厂方法新增具体 Creator;抽象工厂新增实现所有列的具体 Factory。
新增一列(产品等级)工厂方法仍是一列内扩展;抽象工厂需改接口和每个族。
不应由工厂承担把无兼容关系的多个产品方法拼到一个接口。
退回更轻方案的条件只有一种产品等级时选工厂方法,避免抽象工厂过重。

抽象工厂对所有变化并非都开放。它刻意固定列集合,以换取整行切换的一致性;如果系统最常发生的是新增列,工厂接口和所有行实现会频繁联动,此时应拆分工厂边界或选择组合方式。

七、落地验收清单

  1. 为每个具体工厂跑同一组契约测试,确认每个创建方法都返回正确产品等级。
  2. 给产品暴露 familyId() 仅用于测试,校验同一工厂创建的所有产品 familyId 一致。
  3. 加入一个假产品族,记录是否只新增一行实现和装配配置,而未修改旧工厂。
  4. 模拟新增一个产品等级,评估抽象接口和全部具体工厂的真实修改成本。
  5. 检查公共产品接口是否出现 AWS、MySQL、Windows 等具体实现词汇。
  6. 检查具体工厂是否只做组装与创建,没有吞入完整业务流程。
  7. 若产品持有连接或线程池,明确由工厂、容器还是调用方负责关闭。
  8. 若运行期按租户切换工厂,验证路由缓存、凭证刷新和租户隔离。

记忆钩子:工厂方法看一列怎么扩展,抽象工厂看一行怎样成套。

八、常见误区与追问

  • 误区:抽象工厂只是工厂方法返回多个对象。 关键是多个产品等级组成相关产品族。
  • 误区:工厂方法和抽象工厂互斥。 抽象工厂的每个创建方法都可视为一个工厂方法。
  • 误区:创建两个实例就必须抽象工厂。 数量不重要,关系和成套切换才重要。
  • 追问:如何选择模式? 先数产品等级,再判断不同等级是否必须来自同一族。
  • 追问:抽象工厂新增族为何容易? 现有创建方法稳定,新具体工厂实现整套方法即可。
  • 追问:能否把大抽象工厂拆开? 可以按稳定边界拆成多个小工厂,再由组合对象聚合。

九、加强记忆

工厂方法是一条线,抽象工厂是一张网。只有当多种产品需要成套创建、整体切换时,抽象工厂才真正发挥价值。