简单工厂设计模式
简单工厂设计模式
前言
在日常开发中,当我们需要根据不同参数创建不同对象时,代码很容易变成一堆 if-else 的“面条代码”。
**简单工厂模式(Static Factory Method)**正是为了解决这个问题而生:它把所有对象的创建逻辑集中到一个“大工厂”里,让调用方只需要传入一个类型参数,就能拿到统一的接口对象,无需关心具体是哪一个实现类。
本文从简单工厂模式的核心定义与UML结构出发,以两个场景对比“面条代码”与“简单工厂”两种写法:
- LLM模型网关路由;
- 营销发奖系统(优惠券、实物商品、爱奇艺卡三种不同发放逻辑)。
一、 核心定义
简单工厂模式又叫做静态工厂方法模式(Static Factory Method)。
它的核心思想是:由一个专门的“大工厂”类,根据传入的参数,集中包含所有具体对象的创建逻辑,并返回它们的通用接口。
打个比方:简单工厂就像是一个全能的“自动售货机”,你按 1,它给你掉下来可乐;你按 2,它给你掉下来雪碧。售货机(工厂)内部自己搞定了所有的判断逻辑。
二、 标准体系结构图 (UML)
角色说明:
- 抽象产品(Product):定义规范,java中通常是接口。
- 具体产品(ConcreteProduct):实现规范的具体类,用于实现接口。
- 简单工厂(SimpleFactory):包含了必要的判断逻辑,根据外界给定的信息,决定究竟应该创建哪个具体类的对象。
三、 场景推演:LLM 模型网关路由
在开发大模型 Agent 或自进化框架时,底层通常需要接入不同的 LLM 提供商(如 OpenAI, Anthropic, DeepSeek)。
如果使用简单工厂模式来构建这个网关,代码会是这样的:
1. 定义抽象接口
public interface ILLMClient {
String generateText(String prompt);
}
2. 实现具体产品
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. 构建简单工厂(核心所在)
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. 客户端调用
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炼狱,每次修改都有可能不小心改错其他分支,导致线上故障。
五、实战演练:模拟发奖多种商品

实战演练的代码参考小傅哥博客
本文代码仓库:https://github.com/likerhood/CodeDesignWork#
5.1 需求分析
在营销、抽奖等业务场景中,系统往往需要向用户发放多种类型的奖品(如:优惠券、实物商品、第三方兑换卡等)。
- 业务痛点:每种奖品的发放逻辑、所需的参数、以及底层调用的外部接口(可能是不同部门或不同公司提供的 RPC/HTTP 接口)完全不一致。
- 优惠券:需要
uId(用户ID),awardNumber(券码),bizId(防重流水号)。 - 实物商品:需要极度详细的收货信息(姓名、电话、SKU、防重ID、收货地址等)。
- 爱奇艺兑换卡:仅需要用户的
手机号和兑换码。
- 优惠券:需要
- 架构目标:对上层业务(如抽奖接口、前端调用)屏蔽底层的发奖差异,提供一个统一的、高内聚低耦合的发奖网关。
如图:描述了系统参与者(外部系统/用户)与发奖系统之间的功能边界。
5.2 发放奖品的请求体和响应体字段设计
extMap 的 key 约定(发实物商品时必传):
| key | 含义 |
|---|---|
consigneeUserName |
收货人姓名 |
consigneeUserPhone |
收货人手机 |
consigneeUserAddress |
收货地址 |
5.3 简单体系结构图对比
5.3.1 面条代码

5.3.2 简单工厂

5.4 类图对比
5.4.1 面条代码类图
对应仓库中项目模块:codedesign1.0-0
5.4.2 简单工厂类图
5.5 时序图对比
5.5.1 面条代码
5.5.2 简单工厂
总结
简单工厂模式又称静态工厂方法模式,其核心是由一个专门的工厂类(SimpleFactory / StoreFactory)根据传入的参数(如字符串或枚举),集中完成所有具体产品的实例化,并统一返回抽象产品接口(Product / ICommodity)。
核心角色包括:
- 抽象产品(Product / ICommodity)
- 具体产品(ConcreteProductA/B / CouponCommodityService、GoodsCommodityService、CardCommodityService)
- 简单工厂(负责if/switch判断与new对象)
典型应用场景:
- LLM提供商路由(OpenAI、DeepSeek、Claude等)
- 营销发奖系统(不同奖品类型对应不同外部服务)
优点:极简、职责清晰、调用方代码干净,快速实现一定程度的解耦。 最大缺陷:违背开闭原则(OCP),每新增一种产品都必须修改工厂类的判断逻辑,容易形成“巨型switch炼狱”,维护成本随产品种类增加而指数级上升。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)