Skip to content

工厂模式 ​

工厂模式是创建型模式之一,通过工厂类创建对象,而不直接使用new关键字。工厂模式解耦对象的创建和使用,提高代码的可维护性和扩展性。

📋 模式概述 ​

定义: 定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

适用场景:

  • 需要根据条件动态创建对象
  • 对象的创建过程复杂
  • 需要解耦对象的创建和使用
  • 需要统一管理对象的创建

🎯 一、项目案例:支付方式工厂 ​

1.1 问题场景 ​

在电商支付系统中,用户可以选择多种支付方式(支付宝、微信、银行卡等)。如果直接使用if-else创建不同的支付对象,会导致:

  • 代码耦合度高
  • 新增支付方式需要修改现有代码
  • 难以维护和扩展

1.2 工厂模式解决方案 ​

项目背景: 电商支付系统,支持多种支付方式

步骤1:定义支付接口 ​

java
/**
 * 支付接口
 * 项目案例:电商支付系统
 */
public interface Payment {
    
    /**
     * 支付
     * @param amount 支付金额
     * @return 支付结果
     */
    PaymentResult pay(BigDecimal amount);
    
    /**
     * 退款
     * @param orderId 订单号
     * @param amount 退款金额
     * @return 退款结果
     */
    RefundResult refund(String orderId, BigDecimal amount);
    
    /**
     * 查询支付状态
     * @param orderId 订单号
     * @return 支付状态
     */
    PaymentStatus queryStatus(String orderId);
}

步骤2:实现具体的支付方式 ​

java
/**
 * 支付宝支付实现
 */
public class AlipayPayment implements Payment {
    
    private AlipayClient alipayClient;
    
    public AlipayPayment(AlipayClient alipayClient) {
        this.alipayClient = alipayClient;
    }
    
    @Override
    public PaymentResult pay(BigDecimal amount) {
        System.out.println("使用支付宝支付: " + amount);
        // 调用支付宝SDK进行支付
        AlipayTradePayRequest request = new AlipayTradePayRequest();
        request.setBizContent("{" +
            "  \"out_trade_no\":\"" + generateTradeNo() + "\"," +
            "  \"total_amount\":\"" + amount + "\"," +
            "  \"subject\":\"商品购买\"" +
            "}");
        
        try {
            AlipayTradePayResponse response = alipayClient.execute(request);
            return new PaymentResult(response.isSuccess(), response.getTradeNo());
        } catch (Exception e) {
            return new PaymentResult(false, e.getMessage());
        }
    }
    
    @Override
    public RefundResult refund(String orderId, BigDecimal amount) {
        // 支付宝退款逻辑
        System.out.println("支付宝退款: " + orderId + ", 金额: " + amount);
        return new RefundResult(true, "退款成功");
    }
    
    @Override
    public PaymentStatus queryStatus(String orderId) {
        // 查询支付宝支付状态
        return PaymentStatus.SUCCESS;
    }
    
    private String generateTradeNo() {
        return "ALIPAY_" + System.currentTimeMillis();
    }
}
java
/**
 * 微信支付实现
 */
public class WechatPayment implements Payment {
    
    private WxPayService wxPayService;
    
    public WechatPayment(WxPayService wxPayService) {
        this.wxPayService = wxPayService;
    }
    
    @Override
    public PaymentResult pay(BigDecimal amount) {
        System.out.println("使用微信支付: " + amount);
        // 调用微信支付SDK
        WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest();
        request.setTotalFee(amount.multiply(new BigDecimal("100")).intValue());
        request.setOutTradeNo(generateTradeNo());
        request.setBody("商品购买");
        
        try {
            WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(request);
            return new PaymentResult(true, result.getPrepayId());
        } catch (Exception e) {
            return new PaymentResult(false, e.getMessage());
        }
    }
    
    @Override
    public RefundResult refund(String orderId, BigDecimal amount) {
        // 微信退款逻辑
        System.out.println("微信退款: " + orderId + ", 金额: " + amount);
        return new RefundResult(true, "退款成功");
    }
    
    @Override
    public PaymentStatus queryStatus(String orderId) {
        // 查询微信支付状态
        return PaymentStatus.SUCCESS;
    }
    
    private String generateTradeNo() {
        return "WECHAT_" + System.currentTimeMillis();
    }
}
java
/**
 * 银行卡支付实现
 */
public class BankCardPayment implements Payment {
    
    private BankCardService bankCardService;
    
    public BankCardPayment(BankCardService bankCardService) {
        this.bankCardService = bankCardService;
    }
    
    @Override
    public PaymentResult pay(BigDecimal amount) {
        System.out.println("使用银行卡支付: " + amount);
        // 调用银行接口进行支付
        return bankCardService.processPayment(amount);
    }
    
    @Override
    public RefundResult refund(String orderId, BigDecimal amount) {
        // 银行卡退款逻辑
        System.out.println("银行卡退款: " + orderId + ", 金额: " + amount);
        return new RefundResult(true, "退款成功");
    }
    
    @Override
    public PaymentStatus queryStatus(String orderId) {
        // 查询银行卡支付状态
        return PaymentStatus.SUCCESS;
    }
}

步骤3:创建支付工厂 ​

java
/**
 * 支付工厂 - 简单工厂模式
 * 项目案例:电商支付系统
 */
public class PaymentFactory {
    
    // 支付方式枚举
    public enum PaymentType {
        ALIPAY, WECHAT, BANK_CARD
    }
    
    /**
     * 创建支付对象
     * @param paymentType 支付类型
     * @return 支付对象
     */
    public static Payment createPayment(PaymentType paymentType) {
        switch (paymentType) {
            case ALIPAY:
                return new AlipayPayment(createAlipayClient());
            case WECHAT:
                return new WechatPayment(createWxPayService());
            case BANK_CARD:
                return new BankCardPayment(createBankCardService());
            default:
                throw new IllegalArgumentException("不支持的支付方式: " + paymentType);
        }
    }
    
    /**
     * 根据字符串创建支付对象
     */
    public static Payment createPayment(String paymentType) {
        try {
            PaymentType type = PaymentType.valueOf(paymentType.toUpperCase());
            return createPayment(type);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("不支持的支付方式: " + paymentType);
        }
    }
    
    private static AlipayClient createAlipayClient() {
        // 初始化支付宝客户端
        return new DefaultAlipayClient(
            "https://openapi.alipay.com/gateway.do",
            "app_id",
            "private_key",
            "json",
            "UTF-8",
            "alipay_public_key",
            "RSA2"
        );
    }
    
    private static WxPayService createWxPayService() {
        // 初始化微信支付服务
        WxPayConfig config = new WxPayConfig();
        config.setAppId("app_id");
        config.setMchId("mch_id");
        config.setMchKey("mch_key");
        return new WxPayServiceImpl(config);
    }
    
    private static BankCardService createBankCardService() {
        // 初始化银行卡服务
        return new BankCardServiceImpl();
    }
}

步骤4:使用工厂创建支付对象 ​

java
/**
 * 订单服务 - 使用支付工厂
 * 项目案例:电商订单支付
 */
@Service
public class OrderService {
    
    /**
     * 处理订单支付
     */
    public void processPayment(Order order, String paymentType) {
        // 使用工厂创建支付对象
        Payment payment = PaymentFactory.createPayment(paymentType);
        
        // 执行支付
        PaymentResult result = payment.pay(order.getTotalAmount());
        
        if (result.isSuccess()) {
            // 更新订单状态
            order.setStatus(OrderStatus.PAID);
            order.setPaymentTradeNo(result.getTradeNo());
            orderRepository.save(order);
            
            // 发送支付成功通知
            notificationService.sendPaymentSuccessNotification(order);
        } else {
            // 处理支付失败
            handlePaymentFailure(order, result.getErrorMessage());
        }
    }
    
    /**
     * 处理订单退款
     */
    public void processRefund(Order order) {
        // 根据订单的支付方式创建对应的支付对象
        Payment payment = PaymentFactory.createPayment(order.getPaymentType());
        
        // 执行退款
        RefundResult result = payment.refund(order.getOrderId(), order.getTotalAmount());
        
        if (result.isSuccess()) {
            order.setStatus(OrderStatus.REFUNDED);
            orderRepository.save(order);
        }
    }
}

好处:

  1. 解耦: 订单服务不需要知道具体的支付实现类
  2. 易扩展: 新增支付方式只需添加新的实现类和修改工厂
  3. 统一管理: 支付对象的创建逻辑集中在工厂类中

🎯 二、工厂方法模式 ​

2.1 工厂方法模式定义 ​

工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。

2.2 项目案例:数据库连接工厂 ​

项目背景: 微服务系统需要支持多种数据库(MySQL、PostgreSQL、Oracle)

java
/**
 * 数据库连接工厂接口
 */
public interface DatabaseConnectionFactory {
    Connection createConnection();
    DatabaseConnectionPool createConnectionPool();
}
java
/**
 * MySQL连接工厂
 */
public class MySQLConnectionFactory implements DatabaseConnectionFactory {
    
    private String host;
    private int port;
    private String database;
    private String username;
    private String password;
    
    public MySQLConnectionFactory(String host, int port, String database, 
                                  String username, String password) {
        this.host = host;
        this.port = port;
        this.database = database;
        this.username = username;
        this.password = password;
    }
    
    @Override
    public Connection createConnection() throws SQLException {
        String url = "jdbc:mysql://" + host + ":" + port + "/" + database;
        return DriverManager.getConnection(url, username, password);
    }
    
    @Override
    public DatabaseConnectionPool createConnectionPool() {
        return new MySQLConnectionPool(host, port, database, username, password);
    }
}
java
/**
 * PostgreSQL连接工厂
 */
public class PostgreSQLConnectionFactory implements DatabaseConnectionFactory {
    
    private String host;
    private int port;
    private String database;
    private String username;
    private String password;
    
    public PostgreSQLConnectionFactory(String host, int port, String database,
                                       String username, String password) {
        this.host = host;
        this.port = port;
        this.database = database;
        this.username = username;
        this.password = password;
    }
    
    @Override
    public Connection createConnection() throws SQLException {
        String url = "jdbc:postgresql://" + host + ":" + port + "/" + database;
        return DriverManager.getConnection(url, username, password);
    }
    
    @Override
    public DatabaseConnectionPool createConnectionPool() {
        return new PostgreSQLConnectionPool(host, port, database, username, password);
    }
}
java
/**
 * 数据访问层 - 使用工厂方法
 */
public class UserRepository {
    
    private DatabaseConnectionFactory connectionFactory;
    
    public UserRepository(DatabaseConnectionFactory connectionFactory) {
        this.connectionFactory = connectionFactory;
    }
    
    public User findById(Long id) {
        try (Connection conn = connectionFactory.createConnection()) {
            // 查询用户逻辑
            String sql = "SELECT * FROM users WHERE id = ?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setLong(1, id);
            ResultSet rs = ps.executeQuery();
            
            if (rs.next()) {
                return mapToUser(rs);
            }
            return null;
        } catch (SQLException e) {
            throw new RuntimeException("查询用户失败", e);
        }
    }
    
    private User mapToUser(ResultSet rs) throws SQLException {
        User user = new User();
        user.setId(rs.getLong("id"));
        user.setName(rs.getString("name"));
        user.setEmail(rs.getString("email"));
        return user;
    }
}

🎯 三、抽象工厂模式 ​

3.1 抽象工厂模式定义 ​

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

3.2 项目案例:UI组件工厂 ​

项目背景: 跨平台UI系统,支持Windows和Mac两种风格

java
/**
 * UI组件工厂接口
 */
public interface UIFactory {
    Button createButton();
    TextField createTextField();
    Dialog createDialog();
}
java
/**
 * Windows风格UI工厂
 */
public class WindowsUIFactory implements UIFactory {
    
    @Override
    public Button createButton() {
        return new WindowsButton();
    }
    
    @Override
    public TextField createTextField() {
        return new WindowsTextField();
    }
    
    @Override
    public Dialog createDialog() {
        return new WindowsDialog();
    }
}
java
/**
 * Mac风格UI工厂
 */
public class MacUIFactory implements UIFactory {
    
    @Override
    public Button createButton() {
        return new MacButton();
    }
    
    @Override
    public TextField createTextField() {
        return new MacTextField();
    }
    
    @Override
    public Dialog createDialog() {
        return new MacDialog();
    }
}

📖 三种工厂模式对比 ​

模式特点适用场景
简单工厂一个工厂类创建所有对象对象类型较少,创建逻辑简单
工厂方法每个产品对应一个工厂需要扩展产品类型
抽象工厂创建产品族需要创建一系列相关的产品

✅ 学习检查清单 ​

  • [ ] 已理解简单工厂模式
  • [ ] 已理解工厂方法模式
  • [ ] 已理解抽象工厂模式
  • [ ] 已在项目中应用工厂模式
  • [ ] 已了解三种工厂模式的区别和适用场景

上一章节:单例模式
下一章节:策略模式
返回目录:设计模式