简单工厂设计模式
前言
在日常开发中,当我们需要根据不同参数创建不同对象时,代码很容易变成一堆 if-else 的"面条代码"。
简单工厂模式(Static Factory Method) 正是为了解决这个问题而生:它把所有对象的创建逻辑集中到一个"大工厂"里,让调用方只需要传入一个类型参数,就能拿到统一的接口对象,无需关心具体是哪一个实现类。
本文从简单工厂模式的核心定义与UML结构出发,以两个场景对比"面条代码"与"简单工厂"两种写法:
- LLM模型网关路由;
- 营销发奖系统(优惠券、实物商品、爱奇艺卡三种不同发放逻辑)。
一、 核心定义
简单工厂模式又叫做静态工厂方法模式(Static Factory Method)。
它的核心思想是:由一个专门的"大工厂"类,根据传入的参数,集中包含所有具体对象的创建逻辑,并返回它们的通用接口。
打个比方:简单工厂就像是一个全能的"自动售货机",你按 1,它给你掉下来可乐;你按 2,它给你掉下来雪碧。售货机(工厂)内部自己搞定了所有的判断逻辑。
二、 标准体系结构图 (UML)
角色说明:
- 抽象产品(Product):定义规范,java中通常是接口。
- 具体产品(ConcreteProduct):实现规范的具体类,用于实现接口。
- 简单工厂(SimpleFactory):包含了必要的判断逻辑,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。
实现
实现
依赖抽象
实例化 (内部通过 if/switch)
实例化 (内部通过 if/switch)
<<Interface>>
Product
+execute() : void
ConcreteProductA
+execute() : void
ConcreteProductB
+execute() : void
SimpleFactory
+createProduct(type: String) : Product
三、 场景推演:LLM 模型网关路由
在开发大模型 Agent 或自进化框架时,底层通常需要接入不同的 LLM 提供商(如 OpenAI, Anthropic, DeepSeek)。
如果使用简单工厂模式来构建这个网关,代码会是这样的:
1. 定义抽象接口
Java
public interface ILLMClient {
String generateText(String prompt);
}
2. 实现具体产品
Java
public class OpenAIClient implements ILLMClient {
@Override
public String generateText(String prompt) {
return "Calling GPT-4 API: " + prompt;
}
}
public class DeepSeekClient implements ILLMClient {
@Override
public String generateText(String prompt) {
return "Calling DeepSeek-Coder API: " + prompt;
}
}
3. 构建简单工厂(核心所在)
Java
public class LLMFactory {
// 通常设计为静态方法,或者像之前的 StoreFactory 一样提供一个实例方法
public static ILLMClient createClient(String providerType) {
// 核心特征:所有的实例化逻辑都集中在这个 if-else / switch 结构中
if ("openai".equalsIgnoreCase(providerType)) {
return new OpenAIClient();
} else if ("deepseek".equalsIgnoreCase(providerType)) {
return new DeepSeekClient();
} else {
throw new IllegalArgumentException("Unsupported LLM provider: " + providerType);
}
}
}
4. 客户端调用
Java
public class AgentSystem {
public void run() {
// 调用方只需要知道名字,不需要自己去 new 对象
ILLMClient client = LLMFactory.createClient("deepseek");
String response = client.generateText("Analyze this SWE-bench issue...");
}
}
四、 核心优缺点
理解设计模式的关键在于理解它的妥协。
4.1 核心优势
- 极度简单、快速见效 :它确确实实帮调用方(如 Controller 层或 Agent Core)把创建对象的脏活累活干了,调用方变得干净清爽,实现了一定程度上的解耦。
- 职责明确:谁负责用对象,谁负责创建对象,分工清晰。
4.2 缺陷
简单工厂最大的问题在于它违背了"开闭原则(OCP)"。
- 假设你的框架现在需要接入一个新的模型
ClaudeClient,你除了要写一个新的类之外,还必须回头去修改LLMFactory里面的if-else代码。 - 如果系统非常庞大,有 50 种具体产品,这个工厂类的代码将会变成一个巨大的
switch炼狱,每次修改都有可能不小心改错其他分支,导致线上故障。
五、实战演练:模拟发奖多种商品

实战演练的代码参考小傅哥博客
5.1 需求分析
在营销、抽奖等业务场景中,系统往往需要向用户发放多种类型的奖品(如:优惠券、实物商品、第三方兑换卡等)。
- 业务痛点 :每种奖品的发放逻辑、所需的参数、以及底层调用的外部接口(可能是不同部门或不同公司提供的 RPC/HTTP 接口)完全不一致 。
- 优惠券 :需要
uId(用户ID),awardNumber(券码),bizId(防重流水号)。 - 实物商品:需要极度详细的收货信息(姓名、电话、SKU、防重ID、收货地址等)。
- 爱奇艺兑换卡 :仅需要用户的
手机号和兑换码。
- 优惠券 :需要
- 架构目标:对上层业务(如抽奖接口、前端调用)屏蔽底层的发奖差异,提供一个统一的、高内聚低耦合的发奖网关。
如图:描述了系统参与者(外部系统/用户)与发奖系统之间的功能边界。
外部依赖服务
发奖业务系统核心用例
业务客户都安
触发发奖请求
触发发奖请求
触发发奖请求
<> 调用发券接口
<> 调用发货接口
<> 调用发卡接口
触发方
发放优惠券奖品
发放实物商品
发放爱奇艺兑换卡
优惠券服务
物流商品服务
爱奇艺卡服务
5.2 发放奖品的请求体和响应体字段设计
AwardReq
-String uId %% 用户ID
-Integer awardType %% 1优惠券 2实物商品 3爱奇艺卡
-String bizId %% 幂等业务ID防重复
-String awardNumber %% 奖品编号(券号/SKU/卡ID)
-Map<String,String> extMap %% 扩展字段(收货地址等)
+getuId() : String
+getAwardType() : Integer
+getAwardNumber() : String
+getBizId() : String
+getExtMap() : Map
AwardRes
-String code %% 0000成功 0001失败
-String info %% 描述信息
+AwardRes(code, info)
+getCode() : String
+getInfo() : String
extMap 的 key 约定(发实物商品时必传):
| key | 含义 |
|---|---|
consigneeUserName |
收货人姓名 |
consigneeUserPhone |
收货人手机 |
consigneeUserAddress |
收货地址 |
5.3 类图对比
5.3.1 面条代码类图
对应仓库中项目模块:codedesign1.0-0
入参
出参
if awardType==1 直接 new
if awardType==2 直接 new
if awardType==3 直接 new
PrizeController
-Logger logger
+awardToUser(AwardReq req) : AwardRes
-queryUserName(uId) : String
-queryUserPhoneNumber(uId) : String
AwardReq
-String uId
-Integer awardType
-String awardNumber
-String bizId
-Map extMap
AwardRes
-String code
-String info
CouponService
+sendCoupon(uId, couponNumber, uuid) : CouponResult
GoodsService
+deliverGoods(DeliverReq) : Boolean
IQiYiCardService
+grantToken(mobile, cardId) : void
5.3.2 简单工厂类图
入参
出参
持有
创建返回
PrizeController
-Logger logger
-StoreFactory storeFactory
+awardToUser(AwardReq req) : AwardRes
StoreFactory
+getCommodityService(Integer) : ICommodity
+getCommodityService(Class) : ICommodity
<<interface>>
ICommodity
+sendCommodity(uId, commodityId, bizId, extMap) : void
CouponCommodityService
-CouponService couponService
+sendCommodity(...)
GoodsCommodityService
-GoodsService goodsService
+sendCommodity(...)
-queryUserName(uId) : String
-queryUserPhoneNumber(uId) : String
CardCommodityService
-IQiYiCardService iQiYiCardService
+sendCommodity(...)
-queryUserMobile(uId) : String
AwardReq
-String uId
-Integer awardType
-String awardNumber
-String bizId
-Map extMap
AwardRes
-String code
-String info
5.4 简单体系结构图对比
5.4.1 面条代码
外部服务 4.0-0
业务层 单一Controller
客户端
AwardReq
if type==1
if type==2
if type==3
AwardRes
ApiTest
PrizeController
⚠️ 所有逻辑都在这里
CouponService
GoodsService
IQiYiCardService
5.4.2 简单工厂
外部服务 4.0-0
实现层
业务层 分离职责
客户端
AwardReq
返回ICommodity
实现
实现
实现
AwardRes
ApiTest
PrizeController
只负责调用工厂和返回结果
StoreFactory
只负责创建对象
ICommodity
统一接口
CouponCommodityService
GoodsCommodityService
CardCommodityService
CouponService
GoodsService
IQiYiCardService
5.5 时序图对比
5.5.1 面条代码
GoodsService PrizeController ApiTest GoodsService PrizeController ApiTest if type==1 → false else if type==2 → true awardToUser(AwardReq{type=2}) new GoodsService() new DeliverReq() 手动组装7个字段 queryUserName() / queryUserPhoneNumber() deliverGoods(deliverReq) true AwardRes("0000","发放成功")
5.5.2 简单工厂
GoodsService GoodsCommodityService StoreFactory PrizeController ApiTest GoodsService GoodsCommodityService StoreFactory PrizeController ApiTest awardToUser(AwardReq{type=2}) getCommodityService(awardType=2) GoodsCommodityService实例 sendCommodity(uId, sku, bizId, extMap) 组装DeliverReq(职责在这里) deliverGoods(deliverReq) true 正常返回 AwardRes("0000","发放成功")
总结
简单工厂模式又称静态工厂方法模式,其核心是由一个专门的工厂类(SimpleFactory / StoreFactory)根据传入的参数(如字符串或枚举),集中完成所有具体产品的实例化,并统一返回抽象产品接口(Product / ICommodity)。
核心角色包括:
- 抽象产品(Product / ICommodity)
- 具体产品(ConcreteProductA/B / CouponCommodityService、GoodsCommodityService、CardCommodityService)
- 简单工厂(负责if/switch判断与new对象)
典型应用场景:
- LLM提供商路由(OpenAI、DeepSeek、Claude等)
- 营销发奖系统(不同奖品类型对应不同外部服务)
优点 :极简、职责清晰、调用方代码干净,快速实现一定程度的解耦。 最大缺陷:违背开闭原则(OCP),每新增一种产品都必须修改工厂类的判断逻辑,容易形成"巨型switch炼狱",维护成本随产品种类增加而指数级上升。