设计模式之:简单工厂模式

文章目录

    • 什么是简单工厂模式?
    • 核心思想
    • 模式结构
    • 代码示例
      • 场景描述
      • [1. 定义抽象产品接口](#1. 定义抽象产品接口)
      • [2. 实现具体产品类](#2. 实现具体产品类)
      • [3. 创建工厂类](#3. 创建工厂类)
      • [4. 客户端使用示例](#4. 客户端使用示例)
      • [5. 进阶示例:可配置的工厂](#5. 进阶示例:可配置的工厂)
    • 简单工厂模式的优点
      • [1. 封装创建逻辑](#1. 封装创建逻辑)
      • [2. 代码复用](#2. 代码复用)
      • [3. 易于维护](#3. 易于维护)
    • 简单工厂模式的缺点
      • [1. 违反开闭原则](#1. 违反开闭原则)
      • [2. 工厂类职责过重](#2. 工厂类职责过重)
    • 适用场景
    • 最佳实践
      • [1. 使用枚举增强类型安全](#1. 使用枚举增强类型安全)
      • [2. 添加异常处理机制](#2. 添加异常处理机制)
      • [3. 考虑使用配置文件](#3. 考虑使用配置文件)
    • 总结

什么是简单工厂模式?

简单工厂模式(Simple Factory Pattern)是创建型设计模式中最简单的一种,它提供了一个专门的工厂类来负责创建对象的实例,而客户端无需关心具体的创建细节。这种模式通过将对象的创建和使用分离,实现了代码的解耦和复用。

核心思想

简单工厂模式的核心思想是:将对象的创建过程封装在一个工厂类中,客户端只需要知道传入工厂类的参数,而不需要关心对象的具体创建过程。

模式结构

简单工厂模式包含三个主要角色:

  1. 工厂类(Factory):负责创建具体产品对象的核心类
  2. 抽象产品(Product):定义产品的公共接口
  3. 具体产品(Concrete Product):实现抽象产品接口的具体类

代码示例

让我们通过一个完整的示例来深入理解简单工厂模式。

场景描述

假设我们正在开发一个支付系统,需要支持多种支付方式:支付宝、微信支付、银联支付等。使用简单工厂模式可以优雅地管理这些支付方式的创建。

1. 定义抽象产品接口

java 复制代码
/**
 * 支付接口 - 抽象产品角色
 */
public interface Payment {
    /**
     * 支付操作
     * @param amount 支付金额
     * @return 支付结果
     */
    boolean pay(double amount);
    
    /**
     * 获取支付方式名称
     * @return 支付方式名称
     */
    String getPaymentMethod();
}

2. 实现具体产品类

java 复制代码
/**
 * 支付宝支付 - 具体产品角色
 */
public class AlipayPayment implements Payment {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用支付宝支付:" + amount + "元");
        // 模拟支付处理逻辑
        System.out.println("支付宝支付处理中...");
        System.out.println("支付成功!");
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "支付宝支付";
    }
}

/**
 * 微信支付 - 具体产品角色
 */
public class WechatPayment implements Payment {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用微信支付:" + amount + "元");
        // 模拟支付处理逻辑
        System.out.println("微信支付处理中...");
        System.out.println("支付成功!");
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "微信支付";
    }
}

/**
 * 银联支付 - 具体产品角色
 */
public class UnionPayment implements Payment {
    @Override
    public boolean pay(double amount) {
        System.out.println("使用银联支付:" + amount + "元");
        // 模拟支付处理逻辑
        System.out.println("银联支付处理中...");
        System.out.println("支付成功!");
        return true;
    }
    
    @Override
    public String getPaymentMethod() {
        return "银联支付";
    }
}

3. 创建工厂类

java 复制代码
/**
 * 支付工厂类 - 工厂角色
 */
public class PaymentFactory {
    
    /**
     * 创建支付对象
     * @param paymentType 支付类型
     * @return 支付对象
     * @throws IllegalArgumentException 当支付类型不支持时抛出异常
     */
    public static Payment createPayment(String paymentType) {
        if (paymentType == null || paymentType.isEmpty()) {
            throw new IllegalArgumentException("支付类型不能为空");
        }
        
        switch (paymentType.toLowerCase()) {
            case "alipay":
                return new AlipayPayment();
            case "wechat":
                return new WechatPayment();
            case "union":
                return new UnionPayment();
            default:
                throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
        }
    }
    
    /**
     * 使用枚举方式创建支付对象(更安全的方式)
     * @param paymentType 支付类型枚举
     * @return 支付对象
     */
    public static Payment createPayment(PaymentType paymentType) {
        if (paymentType == null) {
            throw new IllegalArgumentException("支付类型不能为空");
        }
        
        switch (paymentType) {
            case ALIPAY:
                return new AlipayPayment();
            case WECHAT:
                return new WechatPayment();
            case UNION:
                return new UnionPayment();
            default:
                throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
        }
    }
}

/**
 * 支付类型枚举
 */
public enum PaymentType {
    ALIPAY, WECHAT, UNION
}

4. 客户端使用示例

java 复制代码
/**
 * 客户端代码 - 使用简单工厂模式
 */
public class Client {
    public static void main(String[] args) {
        // 示例1:使用字符串参数创建支付对象
        System.out.println("=== 使用字符串参数创建支付对象 ===");
        useStringParameter();
        
        System.out.println("\n=== 使用枚举参数创建支付对象 ===");
        // 示例2:使用枚举参数创建支付对象(推荐方式)
        useEnumParameter();
        
        System.out.println("\n=== 错误处理示例 ===");
        // 示例3:错误处理
        handleErrorCases();
    }
    
    private static void useStringParameter() {
        try {
            Payment alipay = PaymentFactory.createPayment("alipay");
            alipay.pay(100.0);
            System.out.println("支付方式:" + alipay.getPaymentMethod());
            
            Payment wechat = PaymentFactory.createPayment("wechat");
            wechat.pay(200.0);
            System.out.println("支付方式:" + wechat.getPaymentMethod());
        } catch (Exception e) {
            System.err.println("支付创建失败: " + e.getMessage());
        }
    }
    
    private static void useEnumParameter() {
        try {
            Payment unionPay = PaymentFactory.createPayment(PaymentType.UNION);
            unionPay.pay(150.0);
            System.out.println("支付方式:" + unionPay.getPaymentMethod());
        } catch (Exception e) {
            System.err.println("支付创建失败: " + e.getMessage());
        }
    }
    
    private static void handleErrorCases() {
        // 测试异常情况
        try {
            PaymentFactory.createPayment("");
        } catch (IllegalArgumentException e) {
            System.err.println("捕获异常: " + e.getMessage());
        }
        
        try {
            PaymentFactory.createPayment("invalid");
        } catch (IllegalArgumentException e) {
            System.err.println("捕获异常: " + e.getMessage());
        }
    }
}

5. 进阶示例:可配置的工厂

java 复制代码
/**
 * 可配置的支付工厂 - 支持从配置文件加载映射关系
 */
public class ConfigurablePaymentFactory {
    private static Map<String, Class<? extends Payment>> paymentMap = new HashMap<>();
    
    static {
        // 初始化默认映射
        paymentMap.put("alipay", AlipayPayment.class);
        paymentMap.put("wechat", WechatPayment.class);
        paymentMap.put("union", UnionPayment.class);
    }
    
    /**
     * 注册新的支付类型
     * @param type 支付类型标识
     * @param paymentClass 支付类
     */
    public static void registerPayment(String type, Class<? extends Payment> paymentClass) {
        paymentMap.put(type, paymentClass);
    }
    
    /**
     * 创建支付对象
     * @param type 支付类型
     * @return 支付对象
     */
    public static Payment createPayment(String type) {
        if (!paymentMap.containsKey(type)) {
            throw new IllegalArgumentException("不支持的支付类型: " + type);
        }
        
        try {
            return paymentMap.get(type).newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            throw new RuntimeException("创建支付对象失败", e);
        }
    }
}

简单工厂模式的优点

1. 封装创建逻辑

java 复制代码
// 客户端代码简洁明了,无需了解具体创建细节
Payment payment = PaymentFactory.createPayment("alipay");
payment.pay(100.0);

2. 代码复用

java 复制代码
// 多个地方使用相同的创建逻辑
public class OrderService {
    public void processOrder(String paymentType, double amount) {
        Payment payment = PaymentFactory.createPayment(paymentType);
        payment.pay(amount);
        // 其他订单处理逻辑...
    }
}

public class RefundService {
    public void processRefund(String paymentType, double amount) {
        Payment payment = PaymentFactory.createPayment(paymentType);
        // 退款处理逻辑...
    }
}

3. 易于维护

当需要添加新的支付方式时,只需要修改工厂类,客户端代码无需改动。

简单工厂模式的缺点

1. 违反开闭原则

java 复制代码
// 添加新的支付方式需要修改工厂类
public static Payment createPayment(String paymentType) {
    switch (paymentType.toLowerCase()) {
        case "alipay":
            return new AlipayPayment();
        case "wechat":
            return new WechatPayment();
        case "union":
            return new UnionPayment();
        // 新增支付方式需要修改这里
        case "newpayment":
            return new NewPayment(); // 需要修改源代码
        default:
            throw new IllegalArgumentException("不支持的支付类型: " + paymentType);
    }
}

2. 工厂类职责过重

当产品类型很多时,工厂类的代码会变得臃肿。

适用场景

  1. 对象创建逻辑相对简单:不需要复杂的创建过程
  2. 客户端不关心具体实现:只需要知道类型标识即可
  3. 产品类型数量有限:不会频繁添加新产品
  4. 需要统一管理对象创建:集中化的创建逻辑

最佳实践

1. 使用枚举增强类型安全

java 复制代码
// 推荐:使用枚举避免字符串硬编码
Payment payment = PaymentFactory.createPayment(PaymentType.ALIPAY);

2. 添加异常处理机制

java 复制代码
public static Payment createPayment(PaymentType paymentType) {
    if (paymentType == null) {
        throw new IllegalArgumentException("支付类型不能为空");
    }
    // ... 创建逻辑
}

3. 考虑使用配置文件

java 复制代码
// 通过配置文件管理类型映射,提高灵活性
Properties props = new Properties();
// 加载配置...
String className = props.getProperty(paymentType);

总结

简单工厂模式虽然简单,但在实际开发中非常实用。它通过将对象的创建和使用分离,提高了代码的灵活性和可维护性。然而,我们也需要认识到它的局限性,特别是在需要频繁扩展的场景下。

关键要点:

  • 简单工厂模式适用于创建逻辑不复杂的场景
  • 通过工厂类封装对象创建细节
  • 客户端与具体产品类解耦
  • 注意违反开闭原则的问题
  • 合理使用枚举和异常处理提高代码质量

掌握简单工厂模式是学习更复杂工厂模式的基础,理解其思想对于编写高质量的面向对象代码具有重要意义。

相关推荐
Lucky_Turtle3 小时前
【Java Xml】dom4j写入XML
xml·java·python
superlls3 小时前
(定时任务)接上篇:定时任务的分布式执行与分布式锁使用场景
java·分布式·后端
无敌的牛3 小时前
C++复习(1)
java·开发语言·面试
子沫20203 小时前
springboot中server.main.web-application-type=reactive导致的拦截器不生效
java·spring boot·后端
kyle~3 小时前
设计模式---观察者模式
服务器·观察者模式·设计模式
Pluchon3 小时前
硅基计划4.0 算法 二叉树深搜(DFS)
java·数据结构·算法·leetcode·深度优先·剪枝
9号达人4 小时前
if-else 优化的折中思考:不是消灭分支,而是控制风险
java·后端·面试
不知道累,只知道类4 小时前
Java 在AWS上使用SDK凭证获取顺序
java·aws
咖啡Beans5 小时前
SpringBoot2.7集成Swagger3.0
java·swagger