← 返回题目列表

简单工厂和工厂方法有什么区别?

高频 简单 第 1 / 25 题 更新于 2026/07/28
工厂方法模式简单工厂开闭原则多态

简化版

简单工厂通常用一个工厂方法加条件分支创建不同产品,新增产品要修改工厂;工厂方法通过抽象工厂和具体工厂创建产品,新增产品主要靠新增工厂类。简单工厂更轻量,工厂方法扩展性更好。

详细版

可以从四个角度比较:

维度简单工厂工厂方法
结构一个工厂类集中创建抽象工厂 + 多个具体工厂
扩展新增产品要改工厂分支新增具体产品和具体工厂
优点简单、类少、上手快更符合开闭原则
适用产品少、变化少产品族持续扩展、创建逻辑复杂

简单工厂并不是没有价值。很多业务中产品只有两三种,变化也很少,用简单工厂能减少样板代码。工厂方法适合产品创建逻辑本身也需要扩展、替换或延迟到子类决定的场景。

面试中可以补一句:工厂方法解决的是“谁来创建具体产品”的扩展问题,不是为了消灭所有 new;如果强行给每个简单对象都配一个工厂,会让设计过度复杂。

完整版教学

一、简单工厂的扩展点在参数

简单工厂常用 type、枚举、配置项来决定创建哪种产品:

static Sender create(SenderType type) {
    return switch (type) {
        case EMAIL -> new EmailSender();
        case SMS -> new SmsSender();
    };
}

扩展点集中在这个方法里,优点是查找创建逻辑很方便;缺点是类型越多,方法越容易膨胀。

二、工厂方法的扩展点在子类

工厂方法会先抽象出工厂接口:

interface SenderFactory {
    Sender createSender();
}

然后用不同具体工厂实现创建逻辑。新增产品时,新建一个实现类就能接入,原有工厂不必跟着改。

三、开闭原则上的差异

开闭原则强调对扩展开放、对修改关闭。简单工厂新增产品常常要改原工厂,容易影响已有产品创建逻辑;工厂方法新增产品主要靠新增类,已有代码更稳定。

但这不是绝对评价。简单工厂在变化少时非常实用,工厂方法在变化多时更稳。面试答案要体现“根据变化点选择设计”,而不是机械套模式。

四、复杂度上的取舍

工厂方法会增加抽象工厂、具体工厂等类型,类数量明显变多。项目小、创建逻辑简单时,过早引入工厂方法会降低可读性。

一个朴素判断标准是:如果每次新增产品都要改同一个工厂,并且改动风险越来越高,就可以考虑工厂方法;如果产品稳定,简单工厂足够。

五、用三种产品和一次扩展计算真实复杂度

简单工厂用一个 switch 管理 EMAIL、SMS、PUSH 三种产品,类少且定位集中;工厂方法把每种创建拆到独立类型。选择不应只看“是否改旧类”,还要比较产品变化频率、构造复杂度和团队理解成本。

简单工厂: create(EMAIL/SMS/PUSH) -> 3 个分支
新增 WEBHOOK -> 修改同一 switch 并补回归
工厂方法: SenderFactory 接口
Email/Sms/Push 各自 Factory
新增 WEBHOOK -> 新增 WebhookFactory
组合根注册 WebhookFactory
业务调用仍依赖 Sender 与 SenderFactory

这段协作图要回答两个不同问题:产品由谁构造,具体工厂又由谁选择。工厂方法可以把产品构造从业务流程中移走,但应用入口、配置层或容器仍然必须决定使用哪个工厂;声称模式“消灭了所有分支”并不准确。

六、模式边界与扩展成本

维度本题结论
稳定抽象两者都应返回 Sender 抽象;差别是创建变化集中在分支还是分散到多态工厂。
主要变化点产品种类与每种产品构造规则。
新增一种产品的动作简单工厂修改中心分支;工厂方法新增具体产品/工厂并装配。
不应放进工厂的职责产品发送行为和渠道业务策略。
更轻或更合适的方案两三种稳定产品选简单工厂;频繁扩展或复杂构造选工厂方法。

是否符合开闭原则不能只数新增了多少类,而要看高风险旧代码是否仍被反复修改。若每次扩展仍要修改一个中心 switch、产品接口又泄漏具体类型,即使类名叫 Factory,也没有获得工厂方法的主要收益。

七、用三个测试验证设计没有走样

  1. 契约测试:对每个具体工厂执行同一组产品接口测试,确认返回值满足抽象契约。
  2. 扩展测试:加入一个假产品和假工厂,记录为了接入它修改了哪些旧文件。
  3. 未知类型测试:若存在注册表或参数路由,明确缺失 key 的异常类型和降级策略。
  4. 生命周期测试:连续创建两次,确认产品应当复用还是隔离,避免无意变成单例或重复昂贵连接。
  5. 依赖测试:具体构造参数应由工厂显式获得,业务类不应通过全局容器偷偷查找。
  6. 并发测试:注册表若支持运行期写入,必须定义发布、覆盖和读取的一致性;只读注册表则尽量启动期冻结。
  7. 可观测性测试:记录命中的工厂 key 与具体实现,排查配置选择错误时无需猜测。

记忆钩子:简单工厂靠参数分流,工厂方法靠类型多态分流。

八、常见误区与追问

  • 误区:简单工厂是 GoF 23 种模式之一。 它是常用创建惯用法,GoF 创建型模式中是工厂方法。
  • 误区:工厂方法在任何项目都优于简单工厂。 它增加类型数量和装配成本,小而稳定场景可能过度。
  • 误区:简单工厂无法测试。 仍可对每个枚举分支做测试,只是扩展修改热点更集中。
  • 追问:静态简单工厂有什么代价? 替换和继承不灵活,依赖也更容易隐藏。
  • 追问:工厂方法的具体工厂由谁创建? 通常由组合根、DI 容器、配置或注册表装配。
  • 追问:何时从简单工厂演进? 当分支持续增长、构造依赖分化、多人频繁修改同一热点时。

九、加强记忆

简单工厂靠参数分流,工厂方法靠多态分流。前者更省类,后者更利于扩展;面试里先讲区别,再讲适用边界,答案会比只背定义更扎实。