14、工厂模式对比:三种工厂模式的适用场景对比表、如何选择

讲完了三种工厂模式的具体实现,你可能会问:「我到底该用哪一种?」

说实话,这个问题我当年也纠结了很久。记得刚带团队那会儿,有个同事把简单工厂和工厂方法混着用,结果项目后期扩展新类型时,改得那叫一个痛苦。后来我花了整整一个下午,把三种模式的适用场景和取舍逻辑理了一遍,才真正搞明白。

今天我就把这份经验直接给你。咱们不绕弯子,直接上对比表,再聊聊怎么选。

三种工厂模式的核心区别

先看一张我亲手画的对比图,把三种模式的结构和决策点说清楚。

三种工厂模式对比总览 简单工厂 • 一个工厂类,switch判断 • 新增产品需改工厂代码 • 适合产品种类少且稳定 工厂方法 • 每个产品对应一个工厂 • 新增产品只需加新工厂类 • 适合中等规模、需扩展 抽象工厂 • 创建产品族(多个产品) • 新增产品族容易,新增产品难 • 适合跨平台、多系列场景 如何选择? 1. 产品种类少且固定 → 简单工厂(别过度设计) 2. 产品种类多且会扩展 → 工厂方法(开闭原则) 3. 需要创建产品族(如不同UI主题) → 抽象工厂 4. 如果只是创建单个复杂对象 → 考虑Builder模式

适用场景对比表

下面这张表我整理了很久,把三种模式从六个维度做了对比。你直接拿去用,面试或做技术选型时都能派上用场。

对比维度 简单工厂 工厂方法 抽象工厂
核心思想 一个工厂类集中创建 每个产品一个工厂子类 创建一组相关产品
扩展性 差(改代码) 好(加类) 好(加产品族)
产品数量 少(<5种) 中等(5-20种) 产品族多
代码复杂度
开闭原则 违反 符合 符合(产品族维度)
典型场景 日志记录器、简单数据源 多种数据库驱动、文档解析 跨平台UI组件、主题系统
我的经验之谈: 别一上来就上抽象工厂。我见过太多项目,明明只需要两三种产品,硬是搞出四五个工厂接口,最后维护成本比写死还高。记住,简单工厂不是坏模式,滥用抽象工厂才是坑

如何选择?三个决策步骤

你不需要背表格。我教你一个三步决策法,每次做选型时走一遍就行。

  1. 数一数产品种类 —— 如果少于5种,且未来一年内不太可能增加,直接上简单工厂。别犹豫。
  2. 看看扩展方向 —— 如果产品种类会持续增加(比如要支持新的数据库、新的文件格式),选工厂方法。它最符合开闭原则。
  3. 判断是否有产品族 —— 如果产品之间有关联,必须一起使用(比如Windows下的按钮+文本框+菜单),那就用抽象工厂。否则别碰。
一个小技巧: 当你拿不准时,先从简单工厂开始。等发现每次新增产品都要改工厂类时,再重构为工厂方法。这叫「渐进式设计」,比一开始就过度设计要靠谱得多。

避坑指南:我曾经踩过的三个坑

这些年我见过不少团队在工厂模式上翻车。说几个典型的,你引以为戒。

  • 坑一:简单工厂里塞了30种产品 —— 那个switch语句长得像裹脚布。每次加新产品都要改工厂,改一次测一次,烦不胜烦。后来我重构成了工厂方法,世界清净了。
  • 坑二:抽象工厂里硬塞不相关的产品 —— 有人把日志记录器和数据库连接放在同一个产品族里。你想想看,这俩东西根本不需要一起创建,强行耦合只会让代码更乱。
  • 坑三:为了用模式而用模式 —— 有个项目只有两种数据库,却搞了四个工厂类。我接手时差点崩溃。记住,模式是工具,不是目的
警告: 如果你发现自己的工厂类里出现了大量的 if-else 或 switch,并且每个分支的代码超过10行,那就是重构的信号。别等到代码发臭再动手。

一个真实案例:从简单工厂到工厂方法

我之前参与过一个报表系统,最初只支持PDF导出。用简单工厂,一个 ReportFactory 搞定。

// 简单工厂版本
public class ReportFactory {
    public Report create(String type) {
        if ("pdf".equals(type)) return new PdfReport();
        // 后来加了 Excel、Word、HTML...
        // 每次都要加 else if,烦死了
    }
}

后来需求爆炸,要支持Excel、Word、HTML、CSV……我果断重构为工厂方法。每个报表类型一个工厂子类,新增类型只需加一个类,不改原有代码。

// 工厂方法版本
public interface ReportFactory {
    Report create();
}
public class PdfReportFactory implements ReportFactory {
    public Report create() { return new PdfReport(); }
}
public class ExcelReportFactory implements ReportFactory {
    public Report create() { return new ExcelReport(); }
}
// 新增时只需加新工厂类,不用改旧代码

这个改动让团队后续半年加了5种新报表,没有一次因为工厂代码出过bug。嗯,这就是模式的力量。

总结一句话

简单工厂图省事,工厂方法图扩展,抽象工厂图产品族。选哪个,取决于你的需求是「稳定」还是「变化」,是「单个产品」还是「产品家族」。

我个人习惯:能用简单工厂解决的问题,绝不用工厂方法;能用工厂方法解决的问题,绝不上抽象工厂。保持简单,保持可控。

公众号:蓝海资料掘金营,微信deep3321