1. 简单工厂模式概述
简单工厂模式(Simple Factory Pattern)是创建型设计模式中最基础的一种,它通过一个工厂类来封装对象的创建逻辑,客户端无需知道具体类的名称,只需要知道工厂类即可获取所需对象。这种模式在需要根据条件动态创建不同类实例的场景中尤为实用。
我在实际项目中发现,当系统需要创建的对象类型较少且创建逻辑不复杂时,简单工厂模式能显著降低代码耦合度。比如电商系统中根据支付方式创建不同的支付处理器,或者根据文件类型创建不同的解析器,都是简单工厂的典型应用场景。
注意:简单工厂模式并不属于GoF 23种设计模式之一,它更像是工厂方法模式的一种简化特例。但由于其简单实用,常被作为学习工厂类模式的入门案例。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 模式结构与核心组件
2.1 UML类图解析
简单工厂模式包含三个核心角色:
- 工厂类(Factory):负责创建具体产品对象的中心类,包含创建对象的静态方法
- 抽象产品(Product):定义产品对象的公共接口
- 具体产品(ConcreteProduct):实现抽象产品接口的具体类
mermaid复制classDiagram
class Factory {
+createProduct(type): Product
}
class Product {
<<interface>>
+operation()
}
class ConcreteProductA {
+operation()
}
class ConcreteProductB {
+operation()
}
Factory --> Product : creates
Product <|-- ConcreteProductA
Product <|-- ConcreteProductB
2.2 代码实现示例
以支付系统为例,我们来看一个典型实现:
java复制// 抽象产品
public interface Payment {
void pay(double amount);
}
// 具体产品
public class Alipay implements Payment {
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount);
}
}
public class WechatPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("微信支付:" + amount);
}
}
// 工厂类
public class PaymentFactory {
public static Payment createPayment(String type) {
switch (type.toLowerCase()) {
case "alipay":
return new Alipay();
case "wechat":
return new WechatPay();
default:
throw new IllegalArgumentException("未知支付类型");
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Payment payment = PaymentFactory.createPayment("alipay");
payment.pay(100.0);
}
}
3. 模式应用场景分析
3.1 适用场景
简单工厂模式特别适合以下情况:
- 需要创建的对象较少(通常不超过5-6种)
- 客户端不关心对象的创建细节
- 对象的创建逻辑相对简单且稳定
- 需要集中管理对象的创建过程
3.2 实际应用案例
案例1:日志记录器
根据配置创建文件日志、控制台日志或数据库日志记录器:
python复制class LoggerFactory:
@staticmethod
def get_logger(log_type):
if log_type == "file":
return FileLogger()
elif log_type == "console":
return ConsoleLogger()
elif log_type == "db":
return DatabaseLogger()
else:
raise ValueError("Invalid logger type")
# 使用示例
logger = LoggerFactory.get_logger("file")
logger.log("Application started")
案例2:图表渲染系统
根据数据格式创建不同的图表渲染器:
typescript复制interface Chart {
render(data: any): void;
}
class PieChart implements Chart {
render(data: any) { /*...*/ }
}
class BarChart implements Chart {
render(data: any) { /*...*/ }
}
class ChartFactory {
static createChart(type: string): Chart {
switch(type) {
case 'pie': return new PieChart();
case 'bar': return new BarChart();
default: throw new Error('Unsupported chart type');
}
}
}
// 使用
const chart = ChartFactory.createChart('pie');
chart.render(salesData);
4. 模式优缺点深度解析
4.1 核心优势
- 解耦客户端与具体实现:客户端只需要知道工厂类和抽象产品接口,无需了解具体产品类的实现细节
- 集中管理对象创建:所有对象的创建逻辑集中在工厂类中,便于统一管理和修改
- 降低代码重复:避免在多个地方重复相同的对象创建代码
- 易于扩展新产品:添加新产品只需修改工厂类,客户端代码基本不受影响
4.2 主要局限
- 违反开闭原则:每次添加新产品都需要修改工厂类,可能引入风险
- 工厂类职责过重:当产品类型很多时,工厂方法会变得庞大复杂
- 难以扩展复杂创建逻辑:不适合需要复杂初始化过程的对象创建
- 静态方法难以继承:大多数实现使用静态工厂方法,导致无法通过继承来改变创建行为
经验分享:在实际项目中,当产品类型超过5种或创建逻辑变得复杂时,建议考虑升级为工厂方法模式或抽象工厂模式。
5. 进阶应用与最佳实践
5.1 使用反射改进工厂
通过反射机制可以避免每次新增产品都要修改工厂类的switch-case语句:
java复制public class EnhancedPaymentFactory {
private static final String PACKAGE = "com.example.payment.";
public static Payment createPayment(String type) {
try {
return (Payment) Class.forName(PACKAGE + type + "Pay")
.getDeclaredConstructor()
.newInstance();
} catch (Exception e) {
throw new RuntimeException("支付类型不支持", e);
}
}
}
5.2 配置文件驱动工厂
将产品类型与具体类的映射关系外置到配置文件中:
xml复制<!-- payments.xml -->
<payments>
<payment type="alipay" class="com.example.Alipay"/>
<payment type="wechat" class="com.example.WechatPay"/>
</payments>
java复制public class ConfigurableFactory {
private static Map<String, Class<?>> paymentMap = new HashMap<>();
static {
// 加载解析payments.xml,初始化paymentMap
}
public static Payment createPayment(String type) {
Class<?> clazz = paymentMap.get(type);
if (clazz == null) throw new IllegalArgumentException("无效支付类型");
try {
return (Payment) clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("创建支付实例失败", e);
}
}
}
5.3 多语言实现差异
不同语言实现简单工厂模式时有一些特性差异:
| 特性 | Java/C# | Python/JavaScript | Go |
|---|---|---|---|
| 接口定义 | 显式interface | 鸭子类型 | interface |
| 工厂方法 | 通常静态 | 类方法或模块函数 | 普通函数 |
| 类型安全 | 编译时检查 | 运行时检查 | 编译时检查 |
| 典型实现 | 类+静态方法 | 模块级函数 | 包级函数 |
6. 常见问题与解决方案
6.1 问题1:如何处理产品初始化参数差异?
场景:不同具体产品需要不同的初始化参数。
解决方案:
- 使用Builder模式配合工厂
- 传递参数Map/Properties
- 延迟初始化(创建后调用初始化方法)
示例:
java复制public interface Configurable {
void init(Map<String, Object> config);
}
public class AdvancedFactory {
public static Product createProduct(String type, Map<String, Object> config) {
Product product = //...创建实例
if (product instanceof Configurable) {
((Configurable) product).init(config);
}
return product;
}
}
