工厂方法模式(Factory Method Pattern)详解
一、工厂方法模式简介
工厂方法模式(Factory Method Pattern) 是一种 创建型设计模式,它定义了一个用于创建对象的接口,但让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
你可以这样理解:
“工厂方法模式就像一家连锁餐厅的‘厨房’——总部规定了做汉堡的流程(接口),但每个城市的分店(子类)自己决定用哪种食材、怎么烹饪。”
换句话说,父类负责定义创建对象的流程,而具体创建哪个类的实例,交给子类来决定。
工厂方法模式:
不再提供一个按钮工厂类来统一负责所有产品的创建,而是将具体按钮的创建过程交给专门的工厂子类去完成
如果出现新的按钮类型,只需要为这种新类型的按钮定义一个具体的工厂类就可以创建该新按钮的实例。
使用简单工厂模式设计的按钮工厂
使用工厂方法模式改进后的按钮工厂
简称为工厂模式(Factory Pattern)。
又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。
工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象。
目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
工厂方法模式包含以下4个角色:
Product(抽象产品)
ConcreteProduct(具体产品)
Factory(抽象工厂)
ConcreteFactory(具体工厂)
二、解决的问题类型
工厂方法模式主要用于解决以下问题:
- 对象的创建过程复杂,需要封装起来;
- 希望解耦对象的使用和创建,避免客户端直接依赖具体类;
- 系统需要在运行时根据条件决定创建哪种类型的对象;
- 避免在代码中大量使用
new
关键字,提高可维护性和扩展性。
三、使用场景
场景 | 示例 |
---|---|
跨平台应用 | 创建不同操作系统的 UI 组件(按钮、文本框等) |
数据访问层 | 根据数据库类型(MySQL、Oracle)创建不同的连接工厂 |
日志系统 | 根据配置创建文件日志、数据库日志或远程日志实现 |
消息通知 | 发送短信、邮件、APP推送等不同渠道的通知 |
客户端不知道它所需要的对象的类(客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体产品对象由具体工厂类创建)。
抽象工厂类通过其子类来指定创建哪个对象。
四、核心概念
- Product(产品接口):定义所有具体产品共有的接口。
- ConcreteProduct(具体产品):实现产品接口的具体类。
- Creator(创建者抽象类或接口):声明工厂方法,返回一个产品对象。
- ConcreteCreator(具体创建者):重写工厂方法,返回具体的产品实例。
五、实际代码案例(Java)
我们以“不同数据库连接”为例,演示工厂方法模式的使用。
1. 定义产品接口:数据库连接
// 数据库连接接口(产品)
interface DatabaseConnection {
void connect();
void query();
}
2. 实现具体产品类
// MySQL 连接实现
class MySqlConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("✅ 正在连接 MySQL 数据库...");
}
@Override
public void query() {
System.out.println("🔍 执行 MySQL 查询...");
}
}
// Oracle 连接实现
class OracleConnection implements DatabaseConnection {
@Override
public void connect() {
System.out.println("✅ 正在连接 Oracle 数据库...");
}
@Override
public void query() {
System.out.println("🔍 执行 Oracle 查询...");
}
}
3. 定义创建者抽象类(工厂接口)
// 抽象工厂类(创建者)
abstract class ConnectionFactory {
// 工厂方法:由子类实现,决定创建哪种连接
public abstract DatabaseConnection createConnection();
// 其他通用逻辑(可选)
public final DatabaseConnection getConnection() {
DatabaseConnection conn = createConnection();
conn.connect();
return conn;
}
}
4. 创建具体工厂类
// MySQL 工厂
class MysqlConnectionFactory extends ConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new MySqlConnection();
}
}
// Oracle 工厂
class OracleConnectionFactory extends ConnectionFactory {
@Override
public DatabaseConnection createConnection() {
return new OracleConnection();
}
}
5. 客户端测试类
public class Client {
public static void main(String[] args) {
// 模拟根据配置选择工厂
String dbType = "mysql"; // 可从配置文件读取
ConnectionFactory factory;
if ("mysql".equalsIgnoreCase(dbType)) {
factory = new MysqlConnectionFactory();
} else if ("oracle".equalsIgnoreCase(dbType)) {
factory = new OracleConnectionFactory();
} else {
throw new IllegalArgumentException("不支持的数据库类型");
}
// 使用工厂获取连接
DatabaseConnection connection = factory.getConnection();
connection.query();
}
}
输出结果:
✅ 正在连接 MySQL 数据库...
🔍 执行 MySQL 查询...
💡 提示:结合 简单工厂 + 工厂方法 或使用 Spring IOC 可进一步解耦工厂选择逻辑。
典型代码
典型的抽象工厂类代码:
interface Factory
{
Product FactoryMethod();
}
典型的具体工厂类代码:
class ConcreteFactory : Factory
{
public Product FactoryMethod()
{
return new ConcreteProduct();
}
}
典型的客户端代码片段:
……
Factory factory;
factory = new ConcreteFactory(); //可通过配置文件实现
Product product;
product = factory.FactoryMethod();
……
其他案例
- 某系统运行日志记录器(Logger)可以通过多种途径保存系统的运行日志,例如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。
为了更好地封装记录器的初始化过程并保证多种记录器切换的灵活性,现使用工厂方法模式设计该系统。(注:在.NET平台下常用的日志记录工具有Log4net、NLog等,.NET Framework也提供了一些用于记录日志的类,例如Debug、Trace、TraceSource等。)
- 电视机工厂
将原有的工厂进行分割,为每种品牌的电视机提供一个子工厂,海尔工厂专门负责生产海尔电视机,海信工厂专门负责生产海信电视机,如果需要生产TCL电视机或创维电视机,只需要对应增加一个新的TCL工厂或创维工厂即可,原有的工厂无须做任何修改,使得整个系统具有更加的灵活性和可扩展性。
六、优缺点分析
优点 | 描述 |
---|---|
✅ 解耦对象的创建与使用 | 客户端不直接依赖具体类,只依赖抽象 |
✅ 符合开闭原则 | 新增产品时只需添加新的具体工厂和产品类,无需修改现有代码 |
✅ 支持多态性创建 | 子类可以灵活决定创建哪种对象 |
✅ 隐藏创建细节 | 客户端无需知道对象是如何创建的 |
缺点 | 描述 |
---|---|
❌ 类数量增多 | 每新增一种产品,就要增加一个工厂类(类爆炸) |
❌ 增加系统复杂度 | 对于简单对象,使用工厂方法反而显得过度设计 |
❌ 客户端仍需知道工厂类型 | 虽然不直接创建产品,但仍需选择具体工厂 |
七、与简单工厂、抽象工厂对比
模式 | 特点 | 适用场景 |
---|---|---|
简单工厂 | 一个工厂类通过条件判断创建不同产品 | 产品种类少且不常扩展 |
工厂方法 | 每个产品对应一个工厂子类 | 需要扩展新产品,强调继承 |
抽象工厂 | 创建一组相关或依赖的产品族 | 多个产品系列,如不同主题的 UI 组件 |
八、最终小结
工厂方法模式是一种非常经典且实用的设计模式,特别适合那些需要灵活创建对象、避免硬编码依赖的场景。它通过将对象的创建延迟到子类,实现了“依赖倒置”原则,提升了系统的可扩展性和可维护性。
在开发框架、工具类库、配置化系统、插件机制等项目中,工厂方法模式被广泛应用(如 Java AWT/Swing 的 GUI 组件创建、JDBC 的 DriverManager
等都体现了类似思想)。
📌 一句话总结:
工厂方法模式就像“开分店”,总店定流程,分店自己招人做饭,既统一标准,又因地制宜。
✅ 推荐使用方式:
- 当对象创建逻辑复杂或需要统一管理时;
- 系统未来可能扩展新的产品类型;
- 希望减少客户端对具体实现类的依赖。
以上部分内容由AI大模型生成,注意识别!