工厂模式:设计与实践
一、什么是工厂模式
1. 权威定义
根据《设计模式:可复用面向对象软件的基础》(GOF著作)定义:工厂模式(Factory Pattern)是一种创建型设计模式,其核心是定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
该模式通过封装对象创建逻辑,将实例化过程与使用过程分离,使得系统在无需修改原有代码的情况下,即可新增所需的产品类型。
2. 模式分类
工厂模式包含三种典型实现形式:
- 简单工厂模式(Simple Factory):由一个工厂类根据参数创建不同类型的产品实例
- 工厂方法模式(Factory Method):定义抽象工厂接口,由具体工厂子类创建对应产品
- 抽象工厂模式(Abstract Factory):创建一系列相关或相互依赖的对象族
二、工厂模式的特点
1. 封装对象创建逻辑
将对象的实例化过程封装在工厂类中,客户端无需知道具体的创建细节(如类名、构造参数等),只需通过工厂接口获取产品对象。
2. 基于接口编程
客户端依赖于产品接口和工厂接口,而非具体实现类,符合依赖倒置原则。
3. 延迟实例化
将产品的实例化延迟到具体工厂类中,使得系统可以在运行时动态决定创建哪种产品。
4. 便于扩展
新增产品类型时,只需添加对应的产品类和工厂类,无需修改现有代码,符合开闭原则。
| 特点 | 说明 |
|---|---|
| 封装创建逻辑 | 实例化过程在工厂中完成,客户端无需关注细节 |
| 接口导向 | 依赖抽象接口而非具体实现,降低耦合度 |
| 延迟实例化 | 运行时动态决定产品类型,提升灵活性 |
| 可扩展性 | 新增产品只需扩展工厂和产品类,符合开闭原则 |
三、工厂模式的标准代码实现
1. 简单工厂模式
// 产品接口
public interface Product {
void operation();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductA operation");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductB operation");
}
}
// 简单工厂类
public class SimpleFactory {
public Product createProduct(String type) {
switch (type) {
case "A":
return new ConcreteProductA();
case "B":
return new ConcreteProductB();
default:
throw new IllegalArgumentException("Invalid product type");
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
SimpleFactory factory = new SimpleFactory();
Product productA = factory.createProduct("A");
productA.operation();
Product productB = factory.createProduct("B");
productB.operation();
}
}
2. 工厂方法模式
// 产品接口
public interface Product {
void operation();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductA operation");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductB operation");
}
}
// 工厂接口
public interface Factory {
Product createProduct();
}
// 具体工厂A
public class ConcreteFactoryA implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
// 具体工厂B
public class ConcreteFactoryB implements Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.operation();
Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.operation();
}
}
3. 抽象工厂模式
// 产品族接口A
public interface ProductA {
void operationA();
}
// 产品族接口B
public interface ProductB {
void operationB();
}
// 具体产品A1
public class ConcreteProductA1 implements ProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA1 operation");
}
}
// 具体产品A2
public class ConcreteProductA2 implements ProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA2 operation");
}
}
// 具体产品B1
public class ConcreteProductB1 implements ProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB1 operation");
}
}
// 具体产品B2
public class ConcreteProductB2 implements ProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB2 operation");
}
}
// 抽象工厂接口
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂1(生产产品族1)
public class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2(生产产品族2)
public class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
ProductB productB1 = factory1.createProductB();
productA1.operationA();
productB1.operationB();
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
ProductB productB2 = factory2.createProductB();
productA2.operationA();
productB2.operationB();
}
}
4. 不同工厂模式特点汇总
| 维度 | 简单工厂模式 | 工厂方法模式 | 抽象工厂模式 |
|---|---|---|---|
| 核心角色 | 单一工厂类负责所有产品创建 | 抽象工厂接口+多个具体工厂子类 | 抽象工厂接口+多个产品族工厂 |
| 产品类型 | 单一产品接口的不同实现 | 单一产品接口的不同实现 | 多个相关产品接口组成的产品族 |
| 创建逻辑 | 基于参数判断创建对应产品 | 每个具体工厂对应一种产品 | 每个工厂创建一整套产品族 |
| 客户端依赖 | 依赖工厂类和产品接口 | 依赖抽象工厂和产品接口 | 依赖抽象工厂和产品接口族 |
| 新增产品 | 需要修改工厂类的判断逻辑 | 只需新增产品类和对应工厂类 | 新增产品族需修改抽象工厂接口 |
| 灵活性 | 低(耦合度高) | 中(符合开闭原则) | 高(适合产品族场景) |
| 实现复杂度 | 简单 | 中等(类数量增加) | 复杂(需管理多个产品接口) |
| 典型应用场景 | 产品类型少且固定的场景 | 产品类型多变但单一产品线 | 需要统一风格的系列产品场景 |
四、支付框架设计中工厂模式的运用
以支付订单工厂为例,说明工厂模式在支付框架中的具体实现:
1. 场景分析
支付系统需要处理多种订单类型(普通支付单、预授权单、分账单等),不同订单的创建逻辑、字段验证和存储方式存在差异,但需统一纳入订单生命周期管理。
2. 设计实现
2.1 抽象订单基类
import java.math.BigDecimal;
import java.time.LocalDateTime;
public abstract class PaymentOrder {
protected String orderId;
protected String merchantId;
protected BigDecimal amount;
protected String currency;
protected String status;
protected LocalDateTime createTime;
protected LocalDateTime updateTime;
public abstract void validate();
public abstract void save();
// 通用getter和setter
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public String getMerchantId() { return merchantId; }
public void setMerchantId(String merchantId) { this.merchantId = merchantId; }
public BigDecimal getAmount() { return amount; }
public void setAmount(BigDecimal amount) { this.amount = amount; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
}
2.2 具体订单实现
// 普通支付订单
public class NormalPaymentOrder extends PaymentOrder {
private String goodsId;
private String goodsName;
private int quantity;
@Override
public void validate() {
if (goodsId == null || goodsId.isEmpty()) {
throw new IllegalArgumentException("商品ID不能为空");
}
if (quantity <= 0) {
throw new IllegalArgumentException("商品数量必须大于0");
}
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
throw new IllegalArgumentException("订单金额必须大于0");
}
}
@Override
public void save() {
// 保存到普通订单表
System.out.println("保存普通支付订单: " + orderId);
// 实际实现中会调用DAO层插入数据库
}
// 特有字段的getter和setter
public String getGoodsId() { return goodsId; }
public void setGoodsId(String goodsId) { this.goodsId = goodsId; }
public String getGoodsName() { return goodsName; }
public void setGoodsName(String goodsName) { this.goodsName = goodsName; }
public int getQuantity() { return quantity; }
public void setQuantity(int quantity) { this.quantity = quantity; }
}
// 预授权订单
public class PreAuthorizationOrder extends PaymentOrder {
private int authExpireHours;
private String authCode;
private BigDecimal preAuthAmount;
@Override
public void validate() {
if (authExpireHours <= 0) {
throw new IllegalArgumentException("预授权有效期必须大于0");
}
if (preAuthAmount == null || preAuthAmount.compareTo(amount) < 0) {
throw new IllegalArgumentException("预授权金额不能小于订单金额");
}
}
@Override
public void save() {
// 保存到预授权订单表
System.out.println("保存预授权订单: " + orderId);
// 实际实现中会调用DAO层插入数据库
}
// 特有字段的getter和setter
public int getAuthExpireHours() { return authExpireHours; }
public void setAuthExpireHours(int authExpireHours) { this.authExpireHours = authExpireHours; }
public String getAuthCode() { return authCode; }
public void setAuthCode(String authCode) { this.authCode = authCode; }
public BigDecimal getPreAuthAmount() { return preAuthAmount; }
public void setPreAuthAmount(BigDecimal preAuthAmount) { this.preAuthAmount = preAuthAmount; }
}
// 分账单
public class SplitPaymentOrder extends PaymentOrder {
private String parentOrderId;
private int splitCount;
private BigDecimal serviceFee;
@Override
public void validate() {
if (parentOrderId == null || parentOrderId.isEmpty()) {
throw new IllegalArgumentException("父订单ID不能为空");
}
if (splitCount <= 0) {
throw new IllegalArgumentException("分账数量必须大于0");
}
if (serviceFee == null) {
throw new IllegalArgumentException("服务费不能为空");
}
}
@Override
public void save() {
// 保存到分账单表
System.out.println("保存分账单: " + orderId);
// 实际实现中会调用DAO层插入数据库
}
// 特有字段的getter和setter
public String getParentOrderId() { return parentOrderId; }
public void setParentOrderId(String parentOrderId) { this.parentOrderId = parentOrderId; }
public int getSplitCount() { return splitCount; }
public void setSplitCount(int splitCount) { this.splitCount = splitCount; }
public BigDecimal getServiceFee() { return serviceFee; }
public void setServiceFee(BigDecimal serviceFee) { this.serviceFee = serviceFee; }
}
2.3 订单工厂实现
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Random;
public class PaymentOrderFactory {
private static final String NORMAL_ORDER_TYPE = "NORMAL";
private static final String PRE_AUTH_ORDER_TYPE = "PRE_AUTH";
private static final String SPLIT_ORDER_TYPE = "SPLIT";
private static final Random RANDOM = new Random();
public static PaymentOrder createOrder(String orderType, Map<String, Object> params) {
PaymentOrder order;
switch (orderType) {
case NORMAL_ORDER_TYPE:
order = createNormalOrder(params);
break;
case PRE_AUTH_ORDER_TYPE:
order = createPreAuthOrder(params);
break;
case SPLIT_ORDER_TYPE:
order = createSplitOrder(params);
break;
default:
throw new IllegalArgumentException("不支持的订单类型: " + orderType);
}
// 设置通用字段
order.setOrderId(generateOrderId(orderType));
order.setStatus("INIT");
order.setCreateTime(LocalDateTime.now());
order.setUpdateTime(LocalDateTime.now());
order.setMerchantId((String) params.get("merchantId"));
order.setCurrency(params.getOrDefault("currency", "CNY").toString());
return order;
}
private static NormalPaymentOrder createNormalOrder(Map<String, Object> params) {
NormalPaymentOrder order = new NormalPaymentOrder();
order.setAmount(new BigDecimal(params.get("amount").toString()));
order.setGoodsId((String) params.get("goodsId"));
order.setGoodsName((String) params.get("goodsName"));
order.setQuantity(Integer.parseInt(params.get("quantity").toString()));
return order;
}
private static PreAuthorizationOrder createPreAuthOrder(Map<String, Object> params) {
PreAuthorizationOrder order = new PreAuthorizationOrder();
order.setAmount(new BigDecimal(params.get("amount").toString()));
order.setPreAuthAmount(new BigDecimal(params.get("preAuthAmount").toString()));
order.setAuthExpireHours(Integer.parseInt(params.get("authExpireHours").toString()));
order.setAuthCode((String) params.get("authCode"));
return order;
}
private static SplitPaymentOrder createSplitOrder(Map<String, Object> params) {
SplitPaymentOrder order = new SplitPaymentOrder();
order.setAmount(new BigDecimal(params.get("amount").toString()));
order.setParentOrderId((String) params.get("parentOrderId"));
order.setSplitCount(Integer.parseInt(params.get("splitCount").toString()));
order.setServiceFee(new BigDecimal(params.get("serviceFee").toString()));
return order;
}
private static String generateOrderId(String orderType) {
String prefix = orderType.substring(0, 2).toUpperCase();
LocalDateTime now = LocalDateTime.now();
return String.format("%s%s%04d",
prefix,
now.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmmss")),
RANDOM.nextInt(10000));
}
}
2.4 客户端使用
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
public class OrderService {
public String createPaymentOrder(String orderType, Map<String, Object> params) {
// 通过工厂创建订单
PaymentOrder order = PaymentOrderFactory.createOrder(orderType, params);
// 执行订单验证和保存
order.validate();
order.save();
return order.getOrderId();
}
public static void main(String[] args) {
OrderService service = new OrderService();
// 创建普通支付订单
Map<String, Object> normalParams = new HashMap<>();
normalParams.put("merchantId", "MCH001");
normalParams.put("amount", "99.99");
normalParams.put("goodsId", "G001");
normalParams.put("goodsName", "测试商品");
normalParams.put("quantity", "1");
String normalOrderId = service.createPaymentOrder("NORMAL", normalParams);
System.out.println("创建普通订单成功: " + normalOrderId);
// 创建预授权订单
Map<String, Object> preAuthParams = new HashMap<>();
preAuthParams.put("merchantId", "MCH001");
preAuthParams.put("amount", "1000.00");
preAuthParams.put("preAuthAmount", "1200.00");
preAuthParams.put("authExpireHours", "24");
preAuthParams.put("authCode", "AUTH123456");
String preAuthOrderId = service.createPaymentOrder("PRE_AUTH", preAuthParams);
System.out.println("创建预授权订单成功: " + preAuthOrderId);
}
}
3. 实现优势
- 集中管理创建逻辑:所有订单的创建逻辑集中在工厂类中,避免在业务代码中散落重复的初始化代码。
- 标准化订单流程:确保同类订单遵循相同的创建和初始化流程,减少因手工创建导致的字段遗漏或错误。
- 简化业务代码:客户端只需调用工厂方法并传入参数,无需关心具体订单类型的实现细节。
- 便于扩展:新增订单类型时,只需添加新的订单类并扩展工厂方法,无需修改现有业务逻辑。
五、开源框架中工厂模式的运用(MyBatis)
MyBatis框架广泛使用了工厂模式,其中SqlSessionFactory是典型代表,采用了工厂方法模式的设计思想。
1. 核心实现分析
1.1 工厂接口定义
// SqlSession工厂接口
public interface SqlSessionFactory {
SqlSession openSession();
SqlSession openSession(boolean autoCommit);
SqlSession openSession(Connection connection);
SqlSession openSession(TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType);
SqlSession openSession(ExecutorType execType, boolean autoCommit);
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
SqlSession openSession(ExecutorType execType, Connection connection);
Configuration getConfiguration();
}
1.2 具体工厂实现
MyBatis提供了DefaultSqlSessionFactory作为SqlSessionFactory的默认实现:
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
// 其他openSession方法实现...
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
}
1.3 工厂构建过程
SqlSessionFactory通过SqlSessionFactoryBuilder创建,这是典型的建造者模式与工厂模式结合:
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
1.4 客户端使用方式
// 构建SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 使用工厂创建SqlSession
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
User user = mapper.selectById(1);
}
2. 工厂模式在MyBatis中的作用
- 封装会话创建逻辑:
SqlSessionFactory封装了SqlSession的创建细节,包括事务管理、执行器类型、数据源等配置。 - 提供统一接口:客户端通过
SqlSessionFactory的标准化方法获取SqlSession,无需关心底层实现差异。 - 支持多种配置方式:通过不同的
openSession()方法重载,支持事务隔离级别、执行器类型等多种参数配置。 - 便于扩展:可以通过实现
SqlSessionFactory接口自定义会话工厂,满足特殊需求。
六、总结
1. 工厂模式的适用场景
- 当系统需要创建多种相关或相似的对象,且客户端无需知道具体创建细节时
- 当需要动态决定创建哪种产品对象,或需要在运行时切换产品类型时
- 当产品类的构造过程复杂,或需要进行额外初始化操作时
- 当需要统一管理对象的创建和生命周期时
2. 三种工厂模式的选择建议
| 模式类型 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 简单工厂 | 产品类型较少且固定的场景 | 实现简单,客户端使用方便 | 新增产品需修改工厂类,违背开闭原则 |
| 工厂方法 | 产品类型较多且可能扩展的场景 | 符合开闭原则,扩展性好 | 类数量增多,系统复杂度提高 |
| 抽象工厂 | 需要创建产品族或对象系列的场景 | 便于管理相关产品族,一致性好 | 扩展新的产品族困难,需要修改抽象工厂接口 |
3. 工厂模式在支付系统中的价值
- 标准化对象创建:统一支付相关对象(订单、渠道、通知等)的创建流程,确保系统一致性
- 降低耦合度:客户端与具体实现类解耦,提高系统的可维护性和可测试性
- 提升扩展性:新增支付渠道、订单类型时,只需扩展工厂和产品类,不影响现有业务
- 便于管理复杂对象:封装支付对象的复杂创建逻辑(如签名、加密、参数校验等)
工厂模式通过将对象创建与使用分离,为支付系统提供了灵活的扩展机制和清晰的架构设计,是构建可扩展、可维护支付框架的重要模式选择。