Appearance
工厂方法模式(Factory Method Pattern)
1. 官方定义
"Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses."
—— 《Design Patterns: Elements of Reusable Object-Oriented Software》(GoF, 1994)
核心:定义一个创建对象的接口,但由子类决定具体实例化哪个类。工厂方法将对象创建延迟到子类。
2. 模式解释
核心思想
- 解耦创建逻辑:将对象的创建与使用分离,调用者无需关心具体实现类。
- 支持扩展:新增产品时只需扩展工厂子类,无需修改已有代码(符合开闭原则)。
典型结构
plaintext
|<<Interface>>|
Product
△
| implements
|
ConcreteProductA ──── ConcreteProductB
△ △
| |
|<<Interface>>| |<<Interface>>|
Creator ConcreteCreatorB
△
|
ConcreteCreatorA
优点
- 灵活性:支持动态切换产品类型(如配置文件驱动)。
- 可维护性:创建逻辑集中管理,修改影响范围小。
- 可扩展性:新增产品只需添加工厂子类,无需改动客户端。
缺点
- 类膨胀:每个产品需对应一个工厂类,增加系统复杂度。
- 过度设计风险:简单对象创建场景可能引入不必要的抽象。
3. 解决的问题
经典场景
- 对象创建依赖运行时条件
- 示例:根据用户配置选择数据库类型(MySQL/Oracle)。
- 需要隔离具体类
- 框架不希望暴露具体实现类(如 Spring 的 BeanFactory)。
- 实现跨平台兼容
- 不同操作系统创建不同风格的 UI 组件(如按钮、窗口)。
4. 实现注意事项
关键实现点
- 工厂接口设计
- 工厂方法通常声明为抽象方法(或接口方法),返回抽象产品类型。
- 产品层级一致性
- 所有具体产品必须实现同一抽象接口或继承同一父类。
- 依赖注入支持
- 可通过配置文件、注解等方式动态绑定工厂实现(如 Spring 的
@Bean
)。
- 可通过配置文件、注解等方式动态绑定工厂实现(如 Spring 的
- 异常处理
- 工厂方法需明确处理创建失败场景(如无效参数、资源不足)。
代码片段示例
java
// 抽象产品
interface Logger {
void log(String message);
}
// 具体产品
class FileLogger implements Logger { /* 写入文件 */ }
class DatabaseLogger implements Logger { /* 写入数据库 */ }
// 抽象工厂
interface LoggerFactory {
Logger createLogger();
}
// 具体工厂
class FileLoggerFactory implements LoggerFactory {
public Logger createLogger() {
return new FileLogger();
}
}
5. 实现变体
三种常见实现方式
类型 | 特点 | 适用场景 |
---|---|---|
简单工厂 | 一个工厂类通过条件分支创建不同产品(严格说不属于标准工厂方法模式) | 产品类型少且固定 |
标准工厂方法 | 每个产品对应一个独立工厂类,通过子类实现创建逻辑 | 需要灵活扩展新产品 |
参数化工厂方法 | 工厂方法接收参数决定创建哪种产品(如 createLogger(type) ) | 产品类型由外部条件动态决定 |
6. 相似模式对比
模式 | 核心区别 |
---|---|
抽象工厂模式 | 关注创建产品家族(一组相关产品),而工厂方法模式创建单一产品 |
建造者模式 | 分步骤构建复杂对象,而工厂方法直接返回完整对象 |
策略模式 | 行为模式,用于算法选择;工厂方法属于创建型模式 |
7. 组合使用场景
常见搭配模式
- 抽象工厂模式
- 场景:需要创建多个关联产品(如 GUI 中的按钮 + 文本框组合)。
- 组合方式:每个产品族使用独立的工厂方法实现。
- 单例模式
- 场景:工厂类本身需要全局唯一(如数据库连接池工厂)。
- 原型模式
- 场景:通过克隆已有对象创建新实例(如游戏中的敌人生成器)。
8. 总结记忆点
- 核心价值:通过子类化实现对象创建的延迟绑定。
- 一句话区分工厂方法 vs 抽象工厂:
- 工厂方法:1 个工厂 → 1 个产品
- 抽象工厂:1 个工厂 → N 个关联产品
- 适用性判断:当系统中存在频繁新增产品类型的需求时优先考虑。