← 返回题目列表

使用抽象工厂模式有哪些常见误区?

高频 中等 第 11 / 25 题 更新于 2026/07/28
抽象工厂模式设计误区过度设计接口设计

简化版

常见误区包括没有产品族也强行使用抽象工厂、把不相关产品塞进同一个工厂、让抽象接口泄漏具体实现细节,以及忽略新增产品等级的成本。抽象工厂的价值在于保证一组相关产品一致创建,不是为了把所有创建代码都集中到一个大工厂里。

详细版

高频误区可以归纳为五类:

  1. 没有产品族概念,只是创建一个对象,却套抽象工厂;
  2. 把不相关产品放进同一个工厂,导致接口越来越臃肿;
  3. 抽象产品接口暴露具体厂商或平台细节;
  4. 忽略新增产品等级会修改所有具体工厂;
  5. 具体工厂承担太多业务逻辑,变成流程编排器。

正确使用时,要先确认产品之间确实有关联,并且需要成套切换。比如云厂商存储和队列可以属于同一产品族,但用户服务、订单服务、支付服务通常不应简单放进同一个抽象工厂。

抽象工厂也不保证产品对象本身线程安全。它只约束创建来源和产品族一致性,生命周期、状态隔离和并发控制仍然要单独设计。

完整版教学

一、误区一:没有产品族也使用抽象工厂

如果系统只有一种产品,例如只创建 Parser,那么工厂方法或简单工厂就够了。抽象工厂需要多个相关产品等级,否则接口会显得空洞。

模式越重,越要有对应的复杂度来支撑。

二、误区二:产品族边界过宽

有些设计把所有对象创建都塞进一个 ApplicationFactory,里面有 createUserService()createOrderDao()createPaymentClient()。这种工厂没有清晰产品族,反而成了全局依赖入口。

好的抽象工厂应该围绕明确上下文组织,例如“某个 UI 风格”“某个数据库方言”“某个云厂商套件”。

三、误区三:抽象接口泄漏具体实现

如果公共接口里出现 setAwsRegion()createMysqlLimitSql() 这类明显偏向某个具体实现的方法,说明抽象层被污染了。

应该把具体配置留在具体工厂内部,或者重新拆分更合适的抽象接口。

一旦泄漏,客户端就会出现 instanceof AwsStorage 或按厂商强转,整套替换只剩表面形式。修复时应回到业务真正稳定的能力交集,把厂商专属能力拆成可选接口或明确放在专属适配层。

四、误区四:把业务流程放进工厂

工厂负责创建对象,不负责完成业务流程。比如 CloudFactory 可以创建 StorageClient 和 QueueClient,但不应该把“上传文件、发送消息、写数据库”的完整业务流程都塞进去。

如果工厂开始编排业务,职责就偏离了创建型模式。

五、用“能否画出产品矩阵”识别是否滥用

如果候选设计只能画出 Parser 一列,没有第二类相关产品,就不存在需要成套保证的一行产品族。反过来,把 UserService、OrderDao、PaymentClient 拼成一行也不成立,因为它们没有共同的风格、平台或兼容约束。

              Parser   Validator
JSON族          JParser  JValidator
XML族           XParser  XValidator
每行产品共享协议/配置并必须兼容
若只有 Parser 一列 -> 工厂方法更轻
若行内对象无兼容关系 -> 不是产品族
抽象工厂只管理相关产品的创建

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

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

评审维度本题结论
产品族不变量同一个具体工厂创建的产品必须来自同一真实上下文并能协同。
新增一行(产品族)新增一整套具体产品和一个具体工厂,旧行通常不改。
新增一列(产品等级)修改抽象工厂并让全部具体工厂补方法,影响面大。
不应由工厂承担跨产品业务编排、万能依赖查询、产品内部算法。
退回更轻方案的条件只有一个产品等级用工厂方法;对象无关联则用多个独立工厂。

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

七、落地验收清单

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

记忆钩子:画不出有意义的“行和列”,就不要使用抽象工厂。

八、常见误区与追问

  • 误区:任何多个 create 方法都构成抽象工厂。 方法创建的产品还必须相关并形成可切换产品族。
  • 误区:ApplicationFactory 把所有对象都放一起更统一。 没有产品族边界会演变成全局 Service Locator。
  • 误区:抽象工厂会让新增任何对象都更容易。 新增产品等级恰恰会修改所有具体工厂。
  • 追问:如何判断两个产品相关? 看它们是否共享平台、协议、主题或兼容约束并需要成套切换。
  • 追问:具体工厂能做业务流程吗? 不应;它负责创建和组装,不负责执行跨产品用例。
  • 追问:产品对象线程安全吗? 模式没有该保证,必须按各产品状态和生命周期单独设计。

九、加强记忆

抽象工厂最怕两个极端:没有产品族还硬套,或者产品族边界大到什么都装。判断它是否合理,就看这一组产品是否真的需要一致创建和整体切换。