🏭 设计模式之工厂模式:从蜜雪冰城到 NestJS,把「new」外包出去

📌 写在最前面:为什么你要读这篇?

在上一篇 NestJS 入门指南中,我们反复提到一个词------工厂模式main.ts 里那行 NestFactory.create(AppModule) 到底是什么原理?为什么不用 new NestApplication()?如果你对这些问题还有点模糊,这篇补充文章就是为你准备的。

本文是 NestJS 系列的番外篇 ,用 蜜雪冰城点奶茶 作为核心比喻,从 GoF 经典定义到三种工厂类型,从一行 demo 拆解到 NestJS 源码对应,把工厂模式拆解得明明白白。全文覆盖:工厂模式定义、三大核心价值、三种类型对比、类与对象实例的区别、优缺点分析、NestJS 实战对应。读完这篇,你不仅懂工厂模式,还能跟面试官聊得明明白白。

📚 本文目录

章节 内容概要 重要度
🧁 工厂模式是什么 蜜雪冰城比喻,一句话讲清楚 ⭐⭐⭐⭐⭐
一、官方定义(GoF) 设计模式经典定义 + 小白翻译 ⭐⭐⭐⭐
二、三种类型对比 简单工厂 / 工厂方法 / 抽象工厂 一张表看懂 ⭐⭐⭐⭐⭐
三、三大核心价值 解耦 + 封装变化 + 多态(附代码) ⭐⭐⭐⭐⭐
四、一行 demo 拆解 MixueFactory.create('ice') 逐词解析 ⭐⭐⭐⭐
五、对应 NestJS 你的 demo 就是 NestFactory 的「教学简化版」 ⭐⭐⭐⭐⭐
六、为什么不用 new 直接 new 的 3 个问题 vs 工厂的 3 个优势 ⭐⭐⭐⭐⭐
七、类 vs 对象实例 最容易混淆的概念,小白记忆口诀 ⭐⭐⭐⭐
八、优缺点 面试必问:工厂模式的优缺点是什么? ⭐⭐⭐⭐
九、一句话总结 全文核心提炼 ⭐⭐⭐⭐⭐
十、参考资料 GoF、NestJS 官方、Refactoring Guru ⭐⭐⭐

🧁 工厂模式是什么?

设计模式是一套被反复使用、经过分类编目的代码设计经验总结,GoF 经典共 23 种。其中 工厂模式 是第一种、也是最为重要的设计模式之一。

你想喝奶茶,不用自己做(流程代码),就找蜜雪冰城(工厂)就可以了。为什么"蜜雪冰城"是工厂?因为去到蜜雪冰城可以点各种各样的奶茶或者其他商品。"工厂"就是这个概念,可以根据不同的需求,生产不同的产品。

所以 NestFactory 就是"蜜雪冰城",满足 App 的各种需要。MixueFactory 帮我们提供工厂里的各种类,并和工厂里五花八门的类解耦。开发者只需要调用 MixueFactory.create(type) 即可。由于工厂里的每个类都实现了相同的 show 接口,由工厂类生产出来的对象实例,可以放心地直接调用(工厂类返回的是 new 出来的实例,不是类本身)。

本文 demo 代码仓库factory-demo(文末附完整示例)

一、工厂模式官方定义(GoF 23 种之一)

"定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。" ------ GoF《设计模式:可复用面向对象软件的基础》

小白翻译 :把 new Xxx() 这件事外包给一个"工厂类",调用方不关心 new 的过程,只传个参数拿成品。

💡 注:GoF 这个官方定义描述的是「工厂方法模式」(第二章里的第二种)。本文 demo 用的「简单工厂」是它的简化版------核心思想完全一致,都是把 new 外包出去。区别只是简单工厂用一个类搞定所有产品,工厂方法每个产品对应一个工厂子类。

二、工厂模式的三种类型

类型 特点 本文 demo 属于哪种
简单工厂(Simple Factory) 一个工厂 + 一个 switch/if,根据参数返回不同产品 ✅ 本文的 MixueFactory 就是这种
工厂方法(Factory Method) 每种产品对应一个工厂子类,新增产品时加新工厂子类(遵循开闭原则)
抽象工厂(Abstract Factory) 一个工厂能造一族相关产品(比如全套 UI 主题:按钮+输入框+下拉框)

📌 本文写的是最基础的简单工厂 ,便于理解。NestJS 的 NestFactory 也是这一类的进阶版。

💡 补充说明:严格来说「简单工厂」不属于 GoF 23 种经典设计模式,它是「工厂方法」的简化版。但它最常用、最好理解,所以作为入门第一个学,很多教材也会放在一起讲。

三、工厂模式的三大核心价值

价值 1:解耦

调用方不再写死具体类名:

javascript 复制代码
// ❌ 不用工厂:调用方写死了 IceCream 这个类名
const drink1 = new IceCream()

// ✅ 用工厂:调用方只关心 'ice' 这个标识
const drink1 = MixueFactory.create('ice')

价值 2:封装变化(扩展容易)

新增"咖啡"口味,只改工厂,调用方代码一行不改:

javascript 复制代码
class MixueFactory {
    static create(type){
      switch(type){
        case 'ice':    return new IceCream()
        case 'lemon':  return new LemonTea()
        case 'milk':   return new MilkTea()
        case 'coffee': return new Coffee()   // 新增,调用方无感知
        default: return null
      }
    }
}

价值 3:多态

所有产品实现相同方法名,调用方统一调用:

javascript 复制代码
const drink1 = MixueFactory.create('ice')
drink1.show()   // 不管返回啥,都能调 show

const drink2 = MixueFactory.create('lemon')
drink2.show()   // 同一个方法名,不同行为 = 多态

四、一行 demo 拆解

javascript 复制代码
const drink1 = MixueFactory.create('ice')
部分 作用
MixueFactory 工厂类(用 static,不需要 new 出实例)
.create 静态方法,工厂对外的"点单接口"
('ice') 参数,告诉工厂要啥
const drink1 接住工厂返回的产品实例
返回值 对象实例new IceCream() 造出来的那个具体冰激凌),不是类本身

五、对应 NestJS 的 NestFactory.create

本文 MixueFactory demo NestJS 的 NestFactory 说明
MixueFactory NestFactory 工厂本身
create(type) create(AppModule) 创建方法
'ice' / 'lemon' / 'milk' 字符串 AppModule 模块对象 传给工厂的"点单参数"
IceCream / LemonTea / MilkTea NestApplication 实例 工厂造出的产品
drink.show() app.listen(3000) 产品对外提供服务
static 方法 static 方法 工厂方法都是 static
同步返回 异步返回(await) ⚠️ NestFactory 是异步的
写死 switch 分支 工厂内部按 @Module 装饰器装配 内部实现不同

📌 一句话:本文的 MixueFactory 是 NestFactory 的"教学简化版",把异步、依赖注入、装饰器解析这些复杂细节都剥掉,只剩"工厂+产品+接口"的骨架。

六、为什么不用 new 直接造?

❌ 不用工厂,直接 new

javascript 复制代码
const drink1 = new IceCream()
const drink2 = new LemonTea()
const drink3 = new MilkTea()

问题

  1. 调用方写死了具体类名,加新口味得改调用方
  2. 没有统一入口,难以统计"店里到底卖啥"
  3. 如果造一个产品要做复杂的初始化(比如烤冰激凌),每个调用方都要复制一遍流程

✅ 用工厂

javascript 复制代码
const drink1 = MixueFactory.create('ice')

优势

  1. 调用方只关心 'ice' 标识,不关心具体类
  2. 新增口味只改工厂,调用方无感知
  3. 复杂初始化藏进工厂,调用方写一行就够

七、深入理解:「类」 vs 「对象实例」

工厂模式里最容易混淆的两个概念------「类」和「对象实例」

概念 解释 例子
蓝图 / 模板 IceCream 这个 class 定义
对象实例 按蓝图造出的具体产品 new IceCream() 造出来的那个具体的冰激凌

工厂 MixueFactory.create('ice') 返回的是 new IceCream() ------ 具体的冰激凌实例 ,所以你才能 drink1.show() 直接调用。

如果返回的是"类"本身,那得这样写(累赘):

javascript 复制代码
const DrinkClass = MixueFactory.create('ice')  // 假设返回的是类
const drink = new DrinkClass()                  // 还得再 new 一次
drink.show()

而工厂模式的价值就是:调用方不用再 new 一次,直接拿到能用的实例

🎯 小白记忆口诀:类 = 冰激凌配方(图纸),对象实例 = 按配方做出来的那根具体冰激凌(能吃)。工厂给你的是「能吃的冰激凌」,不是「配方纸」,所以拿到手就能用。

八、工厂模式的优缺点

✅ 优点

  • 解耦:调用方与具体类解耦,依赖抽象不依赖细节
  • 扩展容易:加新产品只改工厂,调用方无感知
  • 统一入口:所有产品都从工厂出,便于管理和统计
  • 封装复杂初始化 :调用方只写一行 MixueFactory.create('ice')

⚠️ 缺点

  • 工厂类变复杂 :产品越多,switch 越长(简单工厂通病)
  • 违反开闭原则:加新产品要改工厂代码(用"工厂方法"模式可避免,每种产品对应一个工厂子类)

九、一句话总结

工厂模式 = 把"new 对象"这件事外包给专门的工厂,调用方只传参数拿成品,不用关心造的过程。

在 NestJS 里,NestFactory 就是这个"工厂",AppModule 是你点的"菜单",app 是工厂给你的"成品"。const app = await NestFactory.create(AppModule) 这一行就是"点单→出货"的过程。

十、参考资料

🔗 本文与系列文章的关系

本文是 NestJS 系列文章的番外篇 / 补充篇,单独讲解「工厂模式」这一核心概念,是对上一篇中「工厂模式」章节的展开和深化。

📌 上一篇 (主系列第一篇):[NestJS 完全入门指南:2万字讲透 Module/Controller/Service + 实战 CRUD](#NestJS 完全入门指南:2万字讲透 Module/Controller/Service + 实战 CRUD "#")

🔜 下一篇(主系列第二篇):数据库实战 ------ 用 TypeORM 连接 PostgreSQL,让 Todo 数据真正持久化,告别重启丢数据。敬请期待!🚀

我们下一篇(主系列第二篇)见! 🚀

📌 勘误说明:本文为系列番外篇,后续如有代码错误或表述不当,会在评论区置顶更正。建议收藏本文,方便后续查阅更新。

相关推荐
抓哇小菜鸡1 小时前
Spring Boot + 本地大模型(Ollama/DeepSeek) + MyBatis-Plus 企业级智能体数据分析系统从零到一源码全解析
spring boot·后端·mybatis
星火10241 小时前
【LangChain4j系列07】结构化输出与类型安全
人工智能·后端
用户298698530141 小时前
3 种方法,轻松将 PowerPoint 转换为 PDF 格式
人工智能·后端·c#
吃饱了得干活1 小时前
为什么你的Service越写越臃肿?三层架构的“业务逻辑层”是个黑盒
java·后端·架构
何时梦醒1 小时前
Docker 容器化入门:从「我电脑能跑」到「哪台机器都能跑」
后端·docker·面试
颜进强1 小时前
11 - 从需求拆解到 OpenSpec:为什么不要直接敲 /opsx:explore
前端·后端·ai编程
foggyprojects1 小时前
AI 说销售额下降了,哪些客户拖累了结果?
后端
小月土星2 小时前
用设计哲学的眼光重新审视 NestJS——一个 AI 应用后端的思考
nestjs
用户852495071842 小时前
NestJS 架构实战:给后端代码请来一位“项目经理
后端