模式补全
这一节按 八面剖析以理解一个概念 / ljg-learn 的思路整理为 Markdown 版本:先定锚,再用八个方向切开概念,最后压缩成公式、例子、类图和检验题。
定锚
简单工厂模式(创建型)的通行定义:把对象创建集中到一个工厂函数或工厂类中,客户端只提交类型参数,不直接拼装具体类。
常见误解:它不是 GoF 正式模式,也不是万能解耦;新增产品时通常仍要修改工厂。
核心词素:简单=一个入口;工厂=把原料变成产品;模式的隐喻是收银台点单,而不是顾客进厨房。
八刀
历史
它来自对构造逻辑重复的朴素整理,后来常作为学习工厂方法、抽象工厂的第一阶梯。它拐成今天的意思,是因为大家先需要一个低成本入口来隐藏 new。
辩证
反面是客户端到处 new 具体类。更高一层的理解是:简单工厂牺牲一部分开闭原则,换来创建逻辑的集中管理。
现象
像点奶茶时说“少冰拿铁”,你不关心机器怎么打奶泡。业务代码也只说我要哪种对象,不关心构造细节。
语言
简单=一个入口;工厂=把原料变成产品;模式的隐喻是收银台点单,而不是顾客进厨房。
形式
product = Factory.create(type, options)。当 type 分支无限膨胀,或产品族之间有组合约束时,这个公式会失效。
存在
它让人先从“我会创建对象”转向“我会隔离创建原因”。开发者开始意识到 new 本身也是依赖。
美感
它美在把凌乱的门口收成一个柜台:所有创建请求从一个窗口进入,秩序马上出现。
元反思
我们常用“工厂”隐喻理解它,这会遮住它对开闭原则的伤害。换成“前台分诊”隐喻,就更容易看到它适合小规模分流。
内观
我是创建入口。你告诉我类型,我替你决定具体对象。我让客户端少知道一点,但我自己会越来越胖,所以我需要节制。
八刀共同指向的深层结构:简单工厂模式不是为了“炫技”,而是在某个变化点上建立边界,让稳定部分继续稳定,让变化部分有自己的位置。
压缩
公式:简单工厂 = 类型参数 + 集中分支 + 隐藏 new
一句话:简单工厂把“要创建谁”的判断收进一个地方,让客户端先从具体类里松手。
结构图:
Client -> Factory(type) -> Product动机/意图
当客户端散落着大量 new ConcreteProduct() 和类型判断时,创建逻辑会和业务逻辑纠缠在一起。简单工厂的意图是把“根据条件选择并创建哪一个具体产品”的责任集中到一个工厂入口,让客户端只依赖抽象产品或统一返回类型。
结构/角色
Product:抽象产品,定义客户端真正需要使用的能力。ConcreteProduct:具体产品,实现抽象产品接口。Factory:简单工厂,接收类型参数或配置,内部决定实例化哪个具体产品。Client:客户端,只向工厂请求产品,不直接依赖具体产品的构造细节。
典型 UML
classDiagram class Client class Factory { +create(type): Product } class Product { <<interface>> +operation(): void } class ConcreteProductA class ConcreteProductB Product <|.. ConcreteProductA Product <|.. ConcreteProductB Client ..> Factory Factory ..> Product Factory ..> ConcreteProductA Factory ..> ConcreteProductB
使用场景
- 产品种类较少,创建分支还可控。
- 客户端不想知道具体类名、构造参数或初始化顺序。
- 创建逻辑需要集中管理,例如统一校验、日志、默认配置。
- 系统处在早期阶段,暂时不值得引入工厂方法或抽象工厂。
正例:TypeScript
interface Payment {
pay(amount: number): void
}
class WechatPay implements Payment {
pay(amount: number) {
console.log("wechat pay", amount)
}
}
class AliPay implements Payment {
pay(amount: number) {
console.log("alipay pay", amount)
}
}
class PaymentFactory {
static create(type: "wechat" | "ali"): Payment {
if (type === "wechat") return new WechatPay()
return new AliPay()
}
}
const payment = PaymentFactory.create("wechat")
payment.pay(100)正例:UML 类图
classDiagram class Payment { <<interface>> +pay(amount: number): void } class WechatPay class AliPay class PaymentFactory { +create(type): Payment } Payment <|.. WechatPay Payment <|.. AliPay PaymentFactory ..> Payment PaymentFactory ..> WechatPay PaymentFactory ..> AliPay
反例:TypeScript
class OrderService {
pay(type: string, amount: number) {
if (type === "wechat") new WechatPay().pay(amount)
if (type === "ali") new AliPay().pay(amount)
}
}反例:UML 类图
classDiagram class OrderService { +pay(type, amount): void } class WechatPay class AliPay OrderService ..> WechatPay : direct new OrderService ..> AliPay : direct new
掌握检验
- 简单工厂为什么不完全符合开闭原则?
- 什么时候简单工厂已经不够,需要升级为工厂方法或抽象工厂?
- 如果分支越来越多,你会把变化拆到哪里?