👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中... 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
🎵 当你的天空突然下了大雨,那是我在为你炸乌云
文章目录
- 一、入门
- 二、工厂方法模式在框架源码中的运用
- [Java 集合框架中的工厂方法模式](#Java 集合框架中的工厂方法模式)
- [Spring 框架中的工厂方法模式](#Spring 框架中的工厂方法模式)
- 三、总结
一、入门
什么是工厂方法模式?
工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟到子类。
简单工厂方法就是所有的产品都交给一个工厂来处理,而工厂方法是交给多个工厂。
为什么要工厂方法模式?
假设我们正在开发一个支付系统,支持多种支付方式(如支付宝、微信支付、银行卡支付等)。在没有工厂方法模式的情况下,代码可能是这样的:
java
// 支付接口
interface Payment {
void pay(double amount);
}
// 支付宝支付
class Alipay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付: " + amount + " 元");
}
}
// 微信支付
class WechatPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用微信支付: " + amount + " 元");
}
}
// 银行卡支付
class BankCardPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用银行卡支付: " + amount + " 元");
}
}
// 客户端代码
public class PaymentSystem {
public static void main(String[] args) {
String paymentType = "alipay"; // 假设从配置或用户输入中获取支付方式
Payment payment = null;
if (paymentType.equals("alipay")) {
payment = new Alipay();
} else if (paymentType.equals("wechatpay")) {
payment = new WechatPay();
} else if (paymentType.equals("bankcard")) {
payment = new BankCardPay();
} else {
throw new IllegalArgumentException("不支持的支付方式");
}
payment.pay(100.0); // 执行支付
}
}
问题分析
- 代码耦合性高 :
- 客户端代码(PaymentSystem)直接依赖具体的支付实现类(如 Alipay、WechatPay 等)。
- 如果需要新增一种支付方式(如 ApplePay),必须修改客户端代码,增加新的 if-else 分支。
- 违反开闭原则 :
- 开闭原则(Open/Closed Principle)要求软件实体应对扩展开放,对修改关闭。
- 在当前实现中,每次新增支付方式都需要修改客户端代码,而不是通过扩展来实现。
- 代码重复 :
- 如果在多个地方需要创建支付对象,相同的 if-else 逻辑会重复出现,导致代码冗余。
- 难以测试 :
- 客户端代码与具体支付实现类耦合,难以进行单元测试(例如,无法轻松模拟支付对象)。
如何实现工厂方法模式
主要角色
- 抽象产品(Product):定义产品的接口。
- 具体产品(Concrete Product):实现抽象产品接口的具体类。
- 抽象工厂(Creator):声明工厂方法,返回一个产品对象。
- 具体工厂(Concrete Creator):实现工厂方法,返回具体产品的实例。
【案例】支付方式 - 改
抽象产品(Product) :支付方式,Payment
类。
java
// 支付接口
interface Payment {
void pay(double amount);
}
具体产品(Concrete Product) : 支付宝支付(Alipay
类)、微信支付(WechatPay
类)、银行卡支付(BankCardPay
类)。
java
// 支付宝支付
class Alipay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用支付宝支付: " + amount + " 元");
}
}
// 微信支付
class WechatPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用微信支付: " + amount + " 元");
}
}
// 银行卡支付
class BankCardPay implements Payment {
@Override
public void pay(double amount) {
System.out.println("使用银行卡支付: " + amount + " 元");
}
}
抽象工厂(Creator) : 支付工厂,PaymentFactory
类。
java
interface PaymentFactory {
Payment createPayment();
}
具体工厂(Concrete Creator) :AlipayFactory
、WechatPayFactory
、BankCardPayFactory
类
java
// 支付宝支付工厂
class AlipayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new Alipay();
}
}
// 微信支付工厂
class WechatPayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new WechatPay();
}
}
// 银行卡支付工厂
class BankCardPayFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new BankCardPay();
}
}
客户端调用
java
public class PaymentSystem {
// 支付方式与工厂类的映射
private static final Map<String, PaymentFactory> paymentFactories = new HashMap<>();
static {
// 初始化映射关系
paymentFactories.put("alipay", new AlipayFactory());
paymentFactories.put("wechatpay", new WechatPayFactory());
paymentFactories.put("bankcard", new BankCardPayFactory());
}
// 获取支付对象
public static Payment getPayment(String paymentType) {
PaymentFactory factory = paymentFactories.get(paymentType);
if (factory == null) {
throw new IllegalArgumentException("不支持的支付方式: " + paymentType);
}
return factory.createPayment();
}
public static void main(String[] args) {
String paymentType = "alipay"; // 假设从配置或用户输入中获取支付方式
// 获取支付对象并执行支付
Payment payment = getPayment(paymentType);
payment.pay(100.0);
}
}
二、工厂方法模式在框架源码中的运用
Java 集合框架中的工厂方法模式
Java 集合框架中的 Collections
工具类提供了多个静态工厂方法,用于创建不可变集合、同步集合等。
示例:Collections.unmodifiableList()
Collections.unmodifiableList()
是一个工厂方法,用于创建不可修改的列表。
java
public class Collections {
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return new UnmodifiableList<>(list);
}
private static class UnmodifiableList<E> extends UnmodifiableCollection<E>
implements List<E> {
// 具体实现...
}
}
- 工厂方法:
unmodifiableList()
是工厂方法,负责创建UnmodifiableList
对象。 - 客户端:客户端通过调用
unmodifiableList()
方法获取不可修改的列表,而无需关心具体的实现类。
java
List<String> originalList = new ArrayList<>();
originalList.add("A");
originalList.add("B");
List<String> unmodifiableList = Collections.unmodifiableList(originalList);
// unmodifiableList.add("C"); // 抛出 UnsupportedOperationException
- 解耦:客户端不需要知道
UnmodifiableList
的具体实现,只需要通过工厂方法获取对象。 - 安全性:工厂方法返回的对象是不可修改的,保证了数据的安全性。
Spring 框架中的工厂方法模式
Spring 框架广泛使用工厂方法模式来创建和管理 Bean 对象。Spring 的 BeanFactory
和 ApplicationContext
是典型的工厂方法模式的实现。
示例:BeanFactory
BeanFactory 是 Spring 的核心接口,负责创建和管理 Bean 对象。它定义了工厂方法 getBean()
,用于获取 Bean
实例。
java
public interface BeanFactory {
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
// 其他方法...
}
- 工厂方法 :
getBean()
是工厂方法,负责根据名称或类型创建并返回Bean
对象。 - 具体工厂 :Spring 提供了多个
BeanFactory
的实现类,例如DefaultListableBeanFactory
。 - 客户端 :Spring 容器(如
ApplicationContext
)通过调用getBean()
方法来获取Bean
对象。
java
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
MyService myService = context.getBean("myService", MyService.class);
myService.doSomething();
- 解耦 :客户端代码(如 MyService)不需要知道具体的 Bean 创建逻辑,只需要通过
getBean()
方法获取对象。 - 灵活性:Spring 可以通过配置文件或注解动态决定创建哪个 Bean 对象。
三、总结
工厂方法模式的优点
- 解耦
- 工厂方法模式将对象的创建与使用分离,客户端代码只需要依赖抽象的工厂接口和产品接口,而不需要关心具体的实现类。
- 例如,在 Spring 框架中,客户端通过
BeanFactory
获取 Bean 对象,而不需要知道具体的 Bean 实现类。
- 符合开闭原则
- 当需要新增一种产品时,只需新增一个具体工厂类和具体产品类,而无需修改现有代码。
- 例如,在支付系统中,新增一种支付方式(如 ApplePay)时,只需新增
ApplePayFactory
和ApplePay
类,而不需要修改客户端代码。
- 可扩展性
- 工厂方法模式支持动态扩展,可以通过配置文件、依赖注入等方式动态决定使用哪个具体工厂类。
- 例如,在 JDBC 中,可以通过配置文件动态切换数据库驱动。
- 代码复用
- 工厂类的逻辑可以复用在多个地方,避免了重复的创建逻辑。
- 例如,在 Log4j 中,
Logger.getLogger()
方法可以在多个地方复用,而不需要重复编写日志记录器的创建逻辑。
- 易于测试
- 客户端代码依赖于抽象的工厂接口和产品接口,可以通过模拟工厂类来测试客户端代码,而不需要依赖具体的实现类。
工厂方法模式的缺点
- 类的数量增加
- 每新增一种产品,就需要新增一个具体工厂类和具体产品类,导致类的数量增加,系统复杂度提高。
- 例如,在支付系统中,如果有 10 种支付方式,就需要 10 个具体工厂类和 10 个具体产品类。
- 增加了系统抽象性
- 工厂方法模式引入了抽象的工厂接口和产品接口,增加了系统的抽象性,可能会使代码更难理解。
- 例如,对于初学者来说,理解 Spring 的
BeanFactory
和ApplicationContext
可能需要一定的学习成本。
- 不适合简单场景
- 如果对象的创建逻辑非常简单,使用工厂方法模式可能会显得过于复杂,增加不必要的代码量。
- 例如,如果只需要创建一个简单的对象,直接使用 new 关键字可能更合适。
工厂方法模式的适用场景
- 需要动态创建对象
- 当对象的创建逻辑需要根据运行时条件动态决定时,工厂方法模式非常适用。
- 例如,在支付系统中,根据用户选择的支付方式动态创建支付对象。
- 需要解耦对象的创建与使用
- 当客户端代码不需要关心具体对象的创建逻辑时,可以使用工厂方法模式将对象的创建过程封装起来。
- 例如,在 Spring 框架中,客户端通过
BeanFactory
获取 Bean 对象,而不需要知道具体的 Bean 实现类。
- 需要支持多种产品类型
- 当系统需要支持多种产品类型,并且这些产品有共同的接口时,可以使用工厂方法模式。
- 例如,在日志框架中,支持多种日志实现(如文件日志、控制台日志等)。
- 需要符合开闭原则
- 当系统需要频繁扩展新的产品类型,并且希望在不修改现有代码的情况下实现扩展时,可以使用工厂方法模式。
- 例如,在 GUI 库中,支持新增一种控件类型(如按钮、文本框等)。
- 需要集中管理对象的创建逻辑
- 当对象的创建逻辑比较复杂,或者需要在多个地方复用时,可以使用工厂方法模式将创建逻辑集中管理。
- 例如,在 JDBC 中,通过
DriverManager.getConnection()
集中管理数据库连接的创建逻辑。