目录
一、引言:为什么需要工厂模式?
在软件开发中,对象的创建逻辑如果直接散落在代码中,会带来两大问题:
- 代码冗余:重复的
new
操作散布在各处。 - 维护困难:若创建逻辑需要修改(如替换实现类),需到处修改代码。
工厂模式(Factory Pattern)通过封装对象创建过程,将对象的实例化与业务逻辑分离,解决了上述问题。它是 Java 开发中最常用的设计模式之一,尤其在框架设计(如 Spring)和复杂系统开发中广泛应用。
二、简单工厂模式(Simple Factory)
1. 核心思想
通过一个静态工厂类,根据传入的参数(如字符串、枚举)决定创建哪种具体对象。所有对象的创建逻辑集中在一个类中。
2. 代码示例
以“汽车制造”为例:
// 抽象产品接口
public interface Car {
void drive();
}
// 具体产品:跑车
public class SportsCar implements Car {
@Override
public void drive() {
System.out.println("Driving a sports car!");
}
}
// 具体产品:SUV
public class SUVCar implements Car {
@Override
public void drive() {
System.out.println("Driving an suv7ultra!");
}
}
// 简单工厂类
public class SimpleCarFactory {
public static Car createCar(String type) {
if ("sports".equalsIgnoreCase(type)) {
return new SportsCar();
} else if ("suv".equalsIgnoreCase(type)) {
return new SUVCar();
}
throw new IllegalArgumentException("Unknown car type: " + type);
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Car myCar = SimpleCarFactory.createCar("sports");
myCar.drive(); // 输出:Driving a sports car!
}
}
3. 优点与缺点
- 优点:
- ✅ 简单易用,适合产品类型少的场景(如配置读取、日志记录)。
- ✅ 客户端无需关心创建细节,只需传入参数。
- 缺点:
- ❌ 违反开闭原则:新增产品类型需修改工厂类(如增加“电动车”需改动
createCar
方法)。 - ❌ 工厂类职责过重,代码集中度高。
- ❌ 违反开闭原则:新增产品类型需修改工厂类(如增加“电动车”需改动
4. 适用场景
- 产品类型固定且较少(如数据库驱动管理器)。
- 快速实现原型或小型项目。
三、工厂方法模式(Factory Method)
1. 核心思想
定义一个抽象工厂接口,由子类实现具体对象的创建逻辑。将对象的创建延迟到子类,符合开闭原则。
2. 代码示例
延续“汽车制造”案例:
// 抽象工厂接口
public interface CarFactory {
Car createCar();
}
// 具体工厂:跑车工厂
public class SportsCarFactory implements CarFactory {
@Override
public Car createCar() {
return new SportsCar();
}
}
// 具体工厂:SUV工厂
public class SUVCarFactory implements CarFactory {
@Override
public Car createCar() {
return new SUVCar();
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
CarFactory factory = new SportsCarFactory();
Car car = factory.createCar();
car.drive(); // 输出:Driving a sports car!
}
}
3. 优点与缺点
- 优点:
- ✅ 符合开闭原则,新增产品只需添加新工厂类(如增加“电动车工厂”无需修改现有代码)。
- ✅ 解耦客户端与具体类,客户端仅需依赖抽象工厂接口。
- 缺点:
- ❌ 类数量增加(每个产品需对应一个工厂类)。
- ❌ 若产品族较多,可能导致大量工厂类。
4. 适用场景
- 产品类型较多且可能扩展(如游戏角色创建、UI 组件生成)。
- 需要将对象创建逻辑分散到不同子类中。
四、抽象工厂模式(Abstract Factory)
1. 核心思想
提供一个抽象工厂接口,用于创建一组相关或依赖的对象(产品族)。例如,创建不同风格的 UI 组件(按钮、文本框)时,保证它们风格一致。
2. 代码示例
以“电子设备制造”为例:
// 抽象产品:手机
public interface Phone {
void call();
}
// 抽象产品:耳机
public interface Headphones {
void playMusic();
}
// 具体产品:小米手机
public class MiPhone implements Phone {
@Override
public void call() {
System.out.println("Calling with MiPhone...");
}
}
// 具体产品:小米耳机
public class MiHeadphones implements Headphones {
@Override
public void playMusic() {
System.out.println("Playing music with MiHeadphones...");
}
}
// 抽象工厂接口
public interface DeviceFactory {
Phone createPhone();
Headphones createHeadphones();
}
// 具体工厂:小米工厂
public class MiDeviceFactory implements DeviceFactory {
@Override
public Phone createPhone() {
return new MiPhone();
}
@Override
public Headphones createHeadphones() {
return new MiHeadphones();
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
DeviceFactory factory = new MiDeviceFactory();
Phone phone = factory.createPhone();
Headphones headphones = factory.createHeadphones();
phone.call();
headphones.playMusic();
}
}
3. 优点与缺点
- 优点:
- ✅ 保证产品族的一致性(如小米设备统一风格)。
- ✅ 扩展产品族方便(如增加“苹果工厂”只需实现新工厂类)。
- 缺点:
- ❌ 增加系统复杂度(需定义抽象工厂和所有产品接口)。
- ❌ 不支持单独扩展某个产品(需修改所有相关产品接口)。
4. 适用场景
- 需要创建一组关联产品(如跨平台 UI 组件、硬件设备套装)。
- 强调产品族的兼容性和一致性(如 macOS 风格的按钮+文本框)。
五、对比与选择建议
模式 | 目标 | 扩展性 | 代码复杂度 | 适用场景 |
---|---|---|---|---|
简单工厂 | 集中创建单一产品 | 差(需修改工厂类) | 低 | 产品少且固定(如配置读取) |
工厂方法 | 子类决定单一产品 | 高(新增子类即可) | 中 | 产品多且需灵活扩展(如游戏角色) |
抽象工厂 | 统一管理产品族 | 中等(需新增工厂类) | 高 | 产品族关联性强(如跨平台 UI) |
实际开发建议:
- 简单工厂:快速实现原型或产品类型少的场景。
- 工厂方法:需要频繁扩展产品类型的场景(如插件系统)。
- 抽象工厂:需要保证产品族一致性的场景(如框架设计)。
六、进阶技巧与注意事项
-
反射优化简单工厂:
public static Car createCar(Class<? extends Car> clazz) { try { return clazz.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new RuntimeException(e); } }
通过传入类名动态创建对象,减少
if-else
分支 -
防止抽象工厂过重:
- 若只需部分产品,可结合工厂方法模式。
-
实际案例参考:
- Spring 框架:使用工厂方法(如
BeanFactory
)和抽象工厂(如ApplicationContext
)管理 Bean 实例。 - Java Calendar:通过工厂方法(
Calendar.getInstance()
)根据本地化创建日历对象
- Spring 框架:使用工厂方法(如
七、总结
工厂模式是 Java 开发的基石技能,掌握其核心逻辑和差异能帮助你写出更优雅、可维护的代码。初学者可从简单工厂入手,逐步理解工厂方法和抽象工厂的设计理念。在实际项目中,根据需求选择合适的模式,避免过度设计!