1. 什么是工厂方法模式?
工厂方法模式是一种 创建型设计模式,其核心思想是 将对象的创建过程延迟到子类,让子类决定实例化哪个具体类。
- 核心目标:解耦对象的创建逻辑与使用逻辑,提升代码的灵活性和扩展性。
关键角色:
- 抽象产品(Product) :定义产品的接口。
- 具体产品(Concrete Product) :实现抽象产品的具体类。
- 抽象工厂(Creator) :声明工厂方法(
createProduct()
),返回抽象产品类型。 - 具体工厂(Concrete Creator) :重写工厂方法,返回具体产品实例。
2. 应用场景
工厂方法模式适用于以下场景:
- 需要动态扩展产品类型:新增产品只需添加新的工厂子类,无需修改已有代码(符合开闭原则)。
- 对象创建逻辑复杂:将创建过程封装在工厂中,简化客户端调用。
- 框架设计:允许框架用户自定义对象的创建逻辑(如 Spring 的
BeanFactory
)。 - 依赖抽象而非具体实现:客户端仅依赖抽象接口,降低耦合。
典型场景:
- 日志记录器(不同格式的日志:文件、数据库、控制台)。
- 数据库连接池(不同数据库类型:MySQL、PostgreSQL)。
- UI 组件库(跨平台的按钮、文本框)。
3. 工厂方法模式的结构
+-------------------+ +-------------------+
| Creator | | Product |
+-------------------+ +-------------------+
| +factoryMethod() |<>------->| +operation() |
+-------------------+ +-------------------+
▲ ▲
| |
+---------------+-----------+ +-----------+-----------+
| ConcreteCreatorA | | ConcreteProductA |
+---------------------------+ +-----------------------+
| +factoryMethod() { | | +operation() { ... } |
| return new ProductA(); | +-----------------------+
| } |
+---------------------------+
4. 实现方式与代码示例
4.1 基础工厂方法模式
场景:实现一个跨平台的按钮(Windows 和 MacOS 风格)。
步骤:
定义抽象产品:
public interface Button {
void render();
void onClick();
}
定义具体产品:
// Windows 按钮
public class WindowsButton implements Button {
@Override
public void render() {
System.out.println("渲染 Windows 风格按钮");
}
@Override
public void onClick() {
System.out.println("Windows 按钮点击事件");
}
}
// MacOS 按钮
public class MacOSButton implements Button {
@Override
public void render() {
System.out.println("渲染 MacOS 风格按钮");
}
@Override
public void onClick() {
System.out.println("MacOS 按钮点击事件");
}
}
定义抽象工厂:
public abstract class Dialog {
// 工厂方法:由子类实现具体逻辑
public abstract Button createButton();
// 公共逻辑
public void renderDialog() {
Button button = createButton();
button.render();
}
}
定义具体工厂:
// Windows 对话框工厂
public class WindowsDialog extends Dialog {
@Override
public Button createButton() {
return new WindowsButton();
}
}
// MacOS 对话框工厂
public class MacOSDialog extends Dialog {
@Override
public Button createButton() {
return new MacOSButton();
}
}
客户端调用:
public class Client {
public static void main(String[] args) {
// 根据配置选择具体工厂
Dialog dialog;
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
dialog = new WindowsDialog();
} else {
dialog = new MacOSDialog();
}
dialog.renderDialog(); // 渲染对应平台的按钮
}
}
4.2 工厂方法的变体
变体1:参数化工厂方法
通过参数决定创建哪种产品。
public abstract class Dialog {
public Button createButton(String type) {
if (type.equals("primary")) {
return new PrimaryButton();
} else if (type.equals("secondary")) {
return new SecondaryButton();
}
throw new IllegalArgumentException("未知按钮类型");
}
}
变体2:简单工厂(非标准工厂方法)
将工厂方法放在一个单独类中,通过静态方法创建对象。
public class ButtonFactory {
public static Button createButton(String osType) {
if (osType.equals("Windows")) {
return new WindowsButton();
} else if (osType.equals("MacOS")) {
return new MacOSButton();
}
throw new IllegalArgumentException("不支持的系统类型");
}
}
5. 工厂方法模式的优缺点
优点:
- 符合开闭原则:新增产品类型只需添加新工厂类,无需修改已有代码。
- 解耦客户端与具体产品:客户端仅依赖抽象接口。
- 代码可读性高:创建逻辑集中管理,职责清晰。
缺点:
- 类数量增加:每个产品需对应一个工厂类,可能造成类膨胀。
- 复杂度提升:简单场景下可能显得过度设计。
6. 工厂方法模式 vs 其他模式
对比项 | 工厂方法模式 | 抽象工厂模式 | 简单工厂模式 |
---|---|---|---|
核心目标 | 创建单一产品 | 创建产品家族 | 集中化创建对象 |
扩展性 | 通过子类扩展 | 通过新工厂类扩展 | 需修改工厂类代码 |
设计原则 | 符合开闭原则 | 符合开闭原则 | 违反开闭原则 |
7. 实际应用案例
Java 集合框架:
java.util.Collections
中的unmodifiableCollection()
方法返回一个不可修改的集合(工厂方法)。
Spring Framework:
BeanFactory
和ApplicationContext
通过getBean()
方法创建和管理对象。
日志框架:
- Log4j 或 SLF4J 的
LoggerFactory.getLogger()
根据配置返回具体的日志实现类。
- Log4j 或 SLF4J 的
8. 注意事项与最佳实践
优先使用工厂方法模式而非简单工厂:
- 简单工厂违反开闭原则,工厂方法更灵活。
结合依赖注入框架:
- 如 Spring 的
@Bean
注解,通过配置管理工厂。
- 如 Spring 的
避免过度设计:
- 简单场景可直接使用
new
,无需引入工厂。
- 简单场景可直接使用
处理异常和边界条件:
- 工厂方法需对无效参数或配置提供明确错误处理。
9. 总结
工厂方法模式通过 将对象的创建延迟到子类,实现了创建逻辑与业务逻辑的解耦,是构建灵活、可扩展系统的关键工具。
- 适用场景:需支持多态对象创建、动态扩展产品类型、框架设计。
- 核心原则:依赖抽象、开闭原则、单一职责。
- 实践建议:根据需求选择标准工厂方法或变体,结合框架能力优化代码结构。
通过合理应用工厂方法模式,可以显著提升代码的可维护性和扩展性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。