工厂方法模式 (Factory Method Pattern)
模式定义
工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定要实例化哪个类。工厂方法将对象的创建延迟到子类。
简单工厂 vs 工厂方法 vs 抽象工厂
| 特性 | 简单工厂 | 工厂方法 | 抽象工厂 |
|---|---|---|---|
| 创建方式 | 一个工厂类 | 每个产品一个工厂 | 一个工厂创建产品族 |
| 扩展性 | 差(需修改工厂) | 好(新增工厂即可) | 好 |
| 符合原则 | 违反开闭原则 | 符合开闭原则 | 符合开闭原则 |
| 适用场景 | 产品种类少 | 产品种类多 | 产品族 |
实现示例:通知系统
产品接口
java
// 通知产品接口
public interface Notification {
void send(String title, String message);
}
// 邮件通知
public class EmailNotification implements Notification {
@Override
public void send(String title, String message) {
System.out.println("发送邮件通知 - 标题: " + title + ", 内容: " + message);
}
}
// 短信通知
public class SmsNotification implements Notification {
@Override
public void send(String title, String message) {
System.out.println("发送短信通知 - 标题: " + title + ", 内容: " + message);
}
}
// 推送通知
public class PushNotification implements Notification {
@Override
public void send(String title, String message) {
System.out.println("发送推送通知 - 标题: " + title + ", 内容: " + message);
}
}方式一:简单工厂
java
public class NotificationFactory {
public static Notification createNotification(String type) {
if (type == null || type.isEmpty()) {
throw new IllegalArgumentException("通知类型不能为空");
}
switch (type.toLowerCase()) {
case "email":
return new EmailNotification();
case "sms":
return new SmsNotification();
case "push":
return new PushNotification();
default:
throw new IllegalArgumentException("未知的通知类型: " + type);
}
}
}
// 使用
// Notification notification = NotificationFactory.createNotification("email");
// notification.send("标题", "内容");缺点: 每次新增通知类型都需要修改工厂类,违反开闭原则。
方式二:工厂方法模式
java
// 工厂接口
public interface NotificationFactory {
Notification createNotification();
}
// 邮件工厂
public class EmailNotificationFactory implements NotificationFactory {
@Override
public Notification createNotification() {
return new EmailNotification();
}
}
// 短信工厂
public class SmsNotificationFactory implements NotificationFactory {
@Override
public Notification createNotification() {
return new SmsNotification();
}
}
// 推送工厂
public class PushNotificationFactory implements NotificationFactory {
@Override
public Notification createNotification() {
return new PushNotification();
}
}使用示例
java
public class NotificationService {
private final NotificationFactory factory;
public NotificationService(NotificationFactory factory) {
this.factory = factory;
}
public void sendNotification(String title, String message) {
Notification notification = factory.createNotification();
notification.send(title, message);
}
}
// 测试代码
public class FactoryMethodDemo {
public static void main(String[] args) {
// 使用邮件通知
NotificationService emailService = new NotificationService(new EmailNotificationFactory());
emailService.sendNotification("会议通知", "明天下午3点开会");
// 使用短信通知
NotificationService smsService = new NotificationService(new SmsNotificationFactory());
smsService.sendNotification("验证码", "您的验证码是 123456");
// 使用推送通知
NotificationService pushService = new NotificationService(new PushNotificationFactory());
pushService.sendNotification("新消息", "您有一条新的消息");
}
}方式三:泛型工厂方法
使用泛型简化工厂方法的实现。
java
// 泛型工厂接口
public interface GenericFactory<T> {
T create();
}
// 邮件工厂(泛型版本)
public class EmailFactory implements GenericFactory<EmailNotification> {
@Override
public EmailNotification create() {
return new EmailNotification();
}
}
// 短信工厂(泛型版本)
public class SmsFactory implements GenericFactory<SmsNotification> {
@Override
public SmsNotification create() {
return new SmsNotification();
}
}JDK 中的工厂方法
1. Calendar 类
java
// Calendar.getInstance() 就是工厂方法
Calendar calendar = Calendar.getInstance(); // 根据时区返回不同实现2. NumberFormat 类
java
NumberFormat currencyFormat = NumberFormat.getCurrencyInstance();
NumberFormat percentFormat = NumberFormat.getPercentInstance();3. Collection.iterator()
java
List<String> list = new ArrayList<>();
Iterator<String> iterator = list.iterator(); // 每个集合类有自己的迭代器实现实际应用
- Spring BeanFactory: 通过
getBean()方法创建对象 - SLF4J LoggerFactory: 根据配置返回不同的 Logger 实现
- JDBC DriverManager: 根据 URL 创建不同的数据库连接
- 日志框架: Log4j、Logback 等通过工厂方法创建 Logger
优缺点
优点:
- 符合开闭原则,新增产品只需新增工厂
- 每个工厂只负责创建一种产品,职责清晰
- 引入抽象层,提高系统灵活性
缺点:
- 类数量成倍增加,增加系统复杂度
- 增加了系统的抽象性和理解难度