一文讲透 GoF 的 23 种设计模式之工厂方法
工厂方法(Factory Method) 是创建型模式
定义
用一句话概括工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。 它让类的实例化推迟到了子类。

简单工厂
了解工厂方法模式前,我们先了解下简单工厂,既然叫简单工厂,那自然很 “简单”。
它的核心思想非常直接:专门定义一个类(包揽大权),通过接收不同的参数,用 switch 或 if-else 来决定创建并返回哪一种具体的产品实例。
假设我们在开发一个 AI 应用,需要根据不同场景创建不同类型的 AI Agent(比如负责对话的 Agent,和负责处理数据的 Agent)。
第一步:定义产品的共同接口和具体实现
1⚡ java片段// 1. 抽象产品
2public interface AIAgent {
3 voidexecuteTask();
4}
5
6// 2. 具体产品 A:聊天助理
7publicclass ChatAgent implements AIAgent {
8 @Override
9 publicvoidexecuteTask() {
10 System.out.println("ChatAgent: 正在与用户进行自然语言对话...");
11 }
12}
13
14// 2. 具体产品 B:数据分析助理
15publicclass DataAnalysisAgent implements AIAgent {
16 @Override
17 publicvoidexecuteTask() {
18 System.out.println("DataAnalysisAgent: 正在提取并分析核心数据...");
19 }
20}
第二步:创建“简单工厂”类
1⚡ java片段// 3. 简单工厂类 (通常使用静态方法)
2publicclass AIAgentFactory {
3
4 // 根据传入的类型参数,决定实例化哪个具体的 Agent
5 publicstatic AIAgent createAgent(String agentType) {
6 if ("chat".equalsIgnoreCase(agentType)) {
7 return new ChatAgent();
8 } elseif ("data".equalsIgnoreCase(agentType)) {
9 return new DataAnalysisAgent();
10 } else {
11 throw new IllegalArgumentException("未知的 Agent 类型: " + agentType);
12 }
13 }
14}
第三步:客户端调用
1⚡ java片段public class Client {
2 public static void main(String[] args) {
3 // 客户端不需要知道 ChatAgent 和 DataAnalysisAgent 是怎么被 new 出来的
4 // 只需要告诉工厂:“给我一个 chat 类型的 Agent”
5 AIAgent agent1 = AIAgentFactory.createAgent("chat");
6 agent1.executeTask();
7
8 AIAgent agent2 = AIAgentFactory.createAgent("data");
9 agent2.executeTask();
10 }
11}
结合代码,我们可以很直观地看到它的特点:
●优点(省事、解耦):客户端彻底和具体的实现类解耦了。你不需要在业务代码里到处写 new ChatAgent(),把“创建对象”的脏活累活全交给了工厂。
●缺点(牵一发而动全身):它严重违反了“开闭原则”(对扩展开放,对修改关闭)。假设我们现在要引入一个新的 CodingAgent(写代码助手),除了要新建产品类,你必须去修改 AIAgentFactory 里面的 if-else 代码。一旦产品种类极其庞大,这个工厂类就会变得非常臃肿且难以维护。
正是为了解决简单工厂“违反开闭原则”的这个致命缺点,才演进出了工厂方法模式(把这一个大工厂,拆成了一个个不用改代码、只需新增的具体小工厂)。
工厂方法模式的结构与角色
工厂方法模式主要包含四个角色:
●抽象产品 (Product):定义产品的统一接口。
●具体产品 (Concrete Product):实现抽象产品接口的具体类。
●抽象工厂 (Creator):声明返回产品对象的工厂方法。
●具体工厂 (Concrete Creator):重写工厂方法,返回具体的实例化产品

Java 代码实现
1. 定义产品(大模型客户端)
1⚡ java片段// 抽象产品:统一的大模型调用接口
2public interface LLMClient {
3 String generate(String prompt);
4}
5
6// 具体产品 A:Claude 客户端
7publicclass ClaudeClient implements LLMClient {
8 private String modelVersion;
9
10 publicClaudeClient(String modelVersion) { this.modelVersion = modelVersion; }
11
12 @Override
13 public String generate(String prompt) {
14 return"[Claude " + modelVersion + "] 思考并返回结果...";
15 }
16}
17
18// 具体产品 B:OpenAI 客户端
19publicclass OpenAIClient implements LLMClient {
20 private String endpoint;
21
22 publicOpenAIClient(String endpoint) { this.endpoint = endpoint; }
23
24 @Override
25 public String generate(String prompt) {
26 return"[OpenAI API] 处理输入并返回结果...";
27 }
28}
2. 定义创建者(核心:业务骨架 + 工厂方法)
这里是关键:AgentWorkflow 不是一个纯粹的“工厂类”,它是业务类,工厂方法只是它的一部分。
1⚡ java片段// 抽象创建者:Agent 工作流骨架
2public abstract class AgentWorkflow {
3
4 // 核心业务逻辑:定义了标准的处理流程(这其实也是个模板方法)
5 publicvoidprocessTask(String taskContext) {
6 System.out.println("=== 1. 解析任务上下文,提取关键信息 ===");
7
8 // 【灵魂所在】:这里调用工厂方法,拿到一个产品对象。
9 // 父类在此刻完全不知道自己拿到的是 Claude 还是 OpenAI。
10 LLMClient client = createLLMClient();
11
12 System.out.println("=== 2. 请求大模型进行推理 ===");
13 String result = client.generate(taskContext);
14
15 System.out.println("=== 3. 结果后处理并落库 ===\n" + result + "\n");
16 }
17
18 // 【工厂方法】:将实例化具体产品的职责,推迟到子类去实现
19 protected abstract LLMClient createLLMClient();
20}
3. 定义具体创建者(子类重写工厂方法)
1⚡ java片段// 具体创建者 A:基于 Claude 的工作流
2publicclass ClaudeAgentWorkflow extends AgentWorkflow {
3 @Override
4 protected LLMClient createLLMClient() {
5 // 这里封装 Claude 特有的复杂初始化逻辑(比如加载凭证、设置代理等)
6 System.out.println(" -> [工厂方法] 正在初始化 Claude 客户端环境...");
7 return new ClaudeClient("3.5-Sonnet");
8 }
9}
10
11// 具体创建者 B:基于 OpenAI 的工作流
12publicclass OpenAIAgentWorkflow extends AgentWorkflow {
13 @Override
14 protected LLMClient createLLMClient() {
15 System.out.println(" -> [工厂方法] 正在构建 OpenAI 客户端环境...");
16 return new OpenAIClient("https://api.openai.com/v1");
17 }
18}
4. 客户端调用
1⚡ java片段public class Client {
2 publicstaticvoidmain(String[] args) {
3 String task = "编写一段 Python Web 框架对比报告";
4
5 // 场景 1:启动基于 Claude 的 Agent 工作流
6 AgentWorkflow claudeWorkflow = new ClaudeAgentWorkflow();
7 claudeWorkflow.processTask(task);
8
9 // 场景 2:切换为基于 OpenAI 的 Agent 工作流
10 AgentWorkflow openaiWorkflow = new OpenAIAgentWorkflow();
11 openaiWorkflow.processTask(task);
12 }
13}
如果你回看之前的例子,你会发现这个 Demo 解决了一个架构设计上的核心痛点:控制反转 (IoC) 的雏形。
在 AgentWorkflow 这个父类中,业务主流程已经被彻底固化并复用(processTask 方法)。如果在未来,业务需求要求你接入一个全新的本地开源模型(比如 DeepSeek),你不需要修改任何现有的主流程代码,只需要:
●新建一个 DeepSeekClient(实现 LLMClient)。
●新建一个 DeepSeekAgentWorkflow,重写 createLLMClient() 方法返回这个新 Client。
这才是工厂方法模式真正强大的地方:它是为了让高层模块(业务骨架)能够独立于底层模块(具体产品)的创建而存在,从而支撑起大型框架的扩展性。 JDK 里的 Iterable 接口和它的 iterator() 方法,本质上就是这种工厂方法模式的经典体现。
什么时候用?
●你写的“父类流程”需要创建某种对象,但父类不该/不想知道具体类是谁(框架留扩展点的典型方式)。
●你希望通过继承覆写来扩展“产物类型”,让调用方不动、流程不动。
一些具体的场景:
●框架扩展点:工厂方法很常见于“框架规定流程、业务方覆写创建”的场景(你写子类接入框架)。
●Spring 的 FactoryBean:它的语义就是“这个 bean 不是普通 bean,而是用来生产另一个对象的”,并且暴露的是 getObject() 创建出来的对象。
●Java ServiceLoader:通过 SPI 在运行时发现/加载实现类,属于“把具体实现延迟到运行时配置/部署”的一类机制,和“解耦创建与使用”的目标一致。
注意模式的命名
我们回头看一下这个模式为什么叫 Factory Method,而不是干脆叫 Factory ? 这个命名是有讲究的。
核心原因在于:这个模式的灵魂是一个“方法”,而不是一个“类”。
1.“工厂 (Factory)”是一个通俗的广义概念:
在日常沟通中,只要一个类的主要职责是造对象,我们都叫它工厂(比如前面提过的“简单工厂”,它就是一个充斥着 if-else 的具体类)。
2.“工厂方法 (Factory Method)”强调的是面向对象中的“多态”与“继承”:
在 GoF 的定义中,创建对象的逻辑并不是封装在一个独立的、包揽大权的“工厂类”里,而是定义在了一个普通业务类(Creator)的内部,作为一个抽象方法存在。
●这个模式的精髓是:父类定义业务骨架,把其中“需要实例化具体对象”的那一步,挖空成一个方法(也就是 Factory Method)。
●具体的实例化工作,推迟(Defer)到了子类去重写这个方法来实现
