设计模式之:简单工厂模式
文章目录
- 什么是简单工厂模式?
- 核心思想
- 模式结构
- 代码示例
- 场景描述
- 1. 定义抽象产品接口
- 2. 实现具体产品类
- 3. 创建工厂类
- 4. 客户端使用示例
- 5. 进阶示例:可配置的工厂
- 简单工厂模式的优点
- 1. 封装创建逻辑
- 2. 代码复用
- 3. 易于维护
- 简单工厂模式的缺点
- 1. 违反开闭原则
- 2. 工厂类职责过重
- 适用场景
- 最佳实践
- 1. 使用枚举增强类型安全
- 2. 添加异常处理机制
- 3. 考虑使用配置文件
- 总结
什么是简单工厂模式?
简单工厂模式(Simple Factory Pattern)是创建型设计模式中最简单的一种,它提供了一个专门的工厂类来负责创建对象的实例,而客户端无需关心具体的创建细节。这种模式通过将对象的创建和使用分离,实现了代码的解耦和复用。
核心思想
简单工厂模式的核心思想是:将对象的创建过程封装在一个工厂类中,客户端只需要知道传入工厂类的参数,而不需要关心对象的具体创建过程。
模式结构
简单工厂模式包含三个主要角色:
- 工厂类(Factory):负责创建具体产品对象的核心类
- 抽象产品(Product):定义产品的公共接口
- 具体产品(Concrete Product):实现抽象产品接口的具体类
代码示例
让我们通过一个完整的示例来深入理解简单工厂模式。
场景描述
假设我们正在开发一个支付系统,需要支持多种支付方式:支付宝、微信支付、银联支付等。使用简单工厂模式可以优雅地管理这些支付方式的创建。
1. 定义抽象产品接口
/*** 支付接口 - 抽象产品角色*/
public interface Payment {/*** 支付操作* @param amount 支付金额* @return 支付结果*/boolean pay(double amount);/*** 获取支付方式名称* @return 支付方式名称*/String getPaymentMethod();
}
2. 实现具体产品类
/*** 支付宝支付 - 具体产品角色*/
public class AlipayPayment implements Payment {@Overridepublic boolean pay(double amount) {System.out.println("使用支付宝支付:" + amount + "元");// 模拟支付处理逻辑System.out.println("支付宝支付处理中...");System.out.println("支付成功!");return true;}@Overridepublic String getPaymentMethod() {return "支付宝支付";}
}/*** 微信支付 - 具体产品角色*/
public class WechatPayment implements Payment {@Overridepublic boolean pay(double amount) {System.out.println("使用微信支付:" + amount + "元");// 模拟支付处理逻辑System.out.println("微信支付处理中...");System.out.println("支付成功!");return true;}@Overridepublic String getPaymentMethod() {return "微信支付";}
}/*** 银联支付 - 具体产品角色*/
public class UnionPayment implements Payment {@Overridepublic boolean pay(double amount) {System.out.println("使用银联支付:" + amount + "元");// 模拟支付处理逻辑System.out.println("银联支付处理中...");System.out.println("支付成功!");return true;}@Overridepublic String getPaymentMethod() {return "银联支付";}
}
3. 创建工厂类
/*** 支付工厂类 - 工厂角色*/
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. 客户端使用示例
/*** 客户端代码 - 使用简单工厂模式*/
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. 进阶示例:可配置的工厂
/*** 可配置的支付工厂 - 支持从配置文件加载映射关系*/
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. 封装创建逻辑
// 客户端代码简洁明了,无需了解具体创建细节
Payment payment = PaymentFactory.createPayment("alipay");
payment.pay(100.0);
2. 代码复用
// 多个地方使用相同的创建逻辑
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. 违反开闭原则
// 添加新的支付方式需要修改工厂类
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. 使用枚举增强类型安全
// 推荐:使用枚举避免字符串硬编码
Payment payment = PaymentFactory.createPayment(PaymentType.ALIPAY);
2. 添加异常处理机制
public static Payment createPayment(PaymentType paymentType) {if (paymentType == null) {throw new IllegalArgumentException("支付类型不能为空");}// ... 创建逻辑
}
3. 考虑使用配置文件
// 通过配置文件管理类型映射,提高灵活性
Properties props = new Properties();
// 加载配置...
String className = props.getProperty(paymentType);
总结
简单工厂模式虽然简单,但在实际开发中非常实用。它通过将对象的创建和使用分离,提高了代码的灵活性和可维护性。然而,我们也需要认识到它的局限性,特别是在需要频繁扩展的场景下。
关键要点:
- 简单工厂模式适用于创建逻辑不复杂的场景
- 通过工厂类封装对象创建细节
- 客户端与具体产品类解耦
- 注意违反开闭原则的问题
- 合理使用枚举和异常处理提高代码质量
掌握简单工厂模式是学习更复杂工厂模式的基础,理解其思想对于编写高质量的面向对象代码具有重要意义。