设计模式——工厂方法模式

工厂方法模式 (Factory Method Pattern)

什么是工厂方法模式?

工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

简单来说:工厂方法模式就是用一个"工厂"类来创建对象,而不是直接使用new关键字。

生活中的例子

想象一家汽车制造厂

  • 抽象产品:汽车(所有汽车都有共同的特征)
  • 具体产品:奔驰、宝马、奥迪等不同品牌的汽车
  • 抽象工厂:汽车工厂(定义了制造汽车的方法)
  • 具体工厂:奔驰工厂、宝马工厂、奥迪工厂(分别制造对应品牌的汽车)

为什么需要工厂方法模式?

传统方式的问题

java 复制代码
// 直接使用new创建对象
Car car = new Benz();

问题

  1. 客户端与具体类耦合:如果需要换成宝马,必须修改代码
  2. 创建逻辑分散:对象的创建逻辑散落在代码各处
  3. 扩展困难:新增车型时需要修改多处代码

工厂方法模式的优势

java 复制代码
// 使用工厂创建对象
Car car = carFactory.createCar();

优势

  1. 解耦:客户端不需要知道具体创建哪个对象
  2. 统一管理:对象的创建逻辑集中在工厂类中
  3. 易于扩展:新增产品时,只需新增对应的工厂类

工厂方法模式的结构

复制代码
┌─────────────────────┐
│    Product (产品)    │  抽象产品
├─────────────────────┤
│ + operation(): void │
└──────────┬──────────┘
           │ 继承
           ├──┬──────────────────┬──────────────┐
           │                    │              │
┌──────────┴──────┐  ┌───────────┴───────┐  ┌───┴────────┐
│ ConcreteProduct1 │  │ ConcreteProduct2 │  │ ...       │  具体产品
└─────────────────┘  └───────────────────┘  └────────────┘

┌─────────────────────┐
│    Creator (工厂)    │  抽象工厂
├─────────────────────┤
│ + factoryMethod():  │
│   Product           │
│ + anOperation():    │
│   void              │
└──────────┬──────────┘
           │ 继承
           ├──┬──────────────────┬──────────────┐
           │                    │              │
┌──────────┴──────┐  ┌───────────┴───────┐  ┌───┴────────┐
│ ConcreteCreator1 │  │ ConcreteCreator2 │  │ ...       │  具体工厂
└─────────────────┘  └───────────────────┘  └────────────┘

代码示例

1. 定义抽象产品

java 复制代码
/**
 * 抽象产品:日志记录器
 */
public interface Logger {
    /**
     * 记录日志
     */
    void log(String message);
    
    /**
     * 记录错误
     */
    void error(String message);
}

2. 定义具体产品

java 复制代码
/**
 * 具体产品:控制台日志记录器
 */
public class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[INFO] " + message);
    }
    
    @Override
    public void error(String message) {
        System.out.println("[ERROR] " + message);
    }
}

/**
 * 具体产品:文件日志记录器
 */
public class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[FILE LOG] " + message);
    }
    
    @Override
    public void error(String message) {
        System.out.println("[FILE ERROR] " + message);
    }
}

/**
 * 具体产品:数据库日志记录器
 */
public class DatabaseLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("[DB LOG] " + message);
    }
    
    @Override
    public void error(String message) {
        System.out.println("[DB ERROR] " + message);
    }
}

3. 定义抽象工厂

java 复制代码
/**
 * 抽象工厂:日志记录器工厂
 */
public abstract class LoggerFactory {
    /**
     * 工厂方法:创建日志记录器
     */
    public abstract Logger createLogger();
    
    /**
     * 模板方法:记录日志消息
     */
    public void logMessage(String message) {
        Logger logger = createLogger();
        logger.log(message);
    }
    
    /**
     * 模板方法:记录错误消息
     */
    public void logError(String message) {
        Logger logger = createLogger();
        logger.error(message);
    }
}

4. 定义具体工厂

java 复制代码
/**
 * 具体工厂:控制台日志记录器工厂
 */
public class ConsoleLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new ConsoleLogger();
    }
}

/**
 * 具体工厂:文件日志记录器工厂
 */
public class FileLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new FileLogger();
    }
}

/**
 * 具体工厂:数据库日志记录器工厂
 */
public class DatabaseLoggerFactory extends LoggerFactory {
    @Override
    public Logger createLogger() {
        return new DatabaseLogger();
    }
}

5. 使用工厂

java 复制代码
/**
 * 工厂方法模式测试类
 * 演示如何使用工厂方法模式创建不同类型的日志记录器
 */
public class FactoryMethodTest {
    
    public static void main(String[] args) {
        System.out.println("=== 工厂方法模式测试 ===\n");
        
        // 测试控制台日志记录器
        System.out.println("--- 测试控制台日志记录器 ---");
        LoggerFactory consoleFactory = new ConsoleLoggerFactory();
        Logger consoleLogger = consoleFactory.createLogger();
        consoleLogger.log("应用程序启动");
        consoleLogger.error("发生了一个错误");
        
        System.out.println();
        
        // 测试文件日志记录器
        System.out.println("--- 测试文件日志记录器 ---");
        LoggerFactory fileFactory = new FileLoggerFactory();
        Logger fileLogger = fileFactory.createLogger();
        fileLogger.log("用户登录成功");
        fileLogger.error("数据库连接失败");
        
        System.out.println();
        
        // 测试数据库日志记录器
        System.out.println("--- 测试数据库日志记录器 ---");
        LoggerFactory dbFactory = new DatabaseLoggerFactory();
        Logger dbLogger = dbFactory.createLogger();
        dbLogger.log("订单创建成功");
        dbLogger.error("支付网关超时");
        
        System.out.println("\n=== 使用模板方法 ===");
        
        // 使用模板方法
        consoleFactory.logMessage("使用模板方法记录日志");
        consoleFactory.logError("使用模板方法记录错误");
        
        System.out.println();
        
        fileFactory.logMessage("使用模板方法记录日志到文件");
        fileFactory.logError("使用模板方法记录错误到文件");
        
        System.out.println("\n=== 扩展性测试 ===");
        System.out.println("如果需要新增一种日志记录器(如:网络日志),");
        System.out.println("只需:");
        System.out.println("1. 创建 NetworkLogger 实现 Logger 接口");
        System.out.println("2. 创建 NetworkLoggerFactory 继承 LoggerFactory");
        System.out.println("3. 无需修改任何现有代码,符合开闭原则!");
    }
}

工厂方法模式的优点

  1. 符合开闭原则:新增产品时,只需新增对应的工厂类,无需修改现有代码
  2. 代码解耦:客户端与具体产品解耦,只依赖抽象产品
  3. 职责单一:每个具体工厂只负责创建一种产品
  4. 易于测试:可以轻松替换具体工厂进行测试

工厂方法模式的缺点

  1. 类数量增加:每增加一个产品,就需要增加一个具体工厂类
  2. 系统复杂度增加:引入了抽象层,增加了系统的理解难度
  3. 简单场景过度设计:如果产品种类很少,使用工厂方法模式可能显得过于复杂

适用场景

  1. 不知道具体要创建哪个产品:客户端只知道需要产品,但不知道具体是哪个
  2. 希望将创建逻辑延迟到子类:让子类决定创建哪个具体产品
  3. 产品种类较多:有多种产品需要创建,且可能继续增加
  4. 需要解耦客户端和具体产品:客户端不依赖具体产品类

常见应用场景

  • 日志框架:不同类型的日志记录器(文件日志、控制台日志、数据库日志)
  • 数据库连接:不同类型的数据库连接(MySQL、Oracle、PostgreSQL)
  • 支付系统:不同的支付方式(支付宝、微信、银行卡)
  • 消息队列:不同的消息队列实现(RabbitMQ、Kafka、ActiveMQ)

与简单工厂的区别

特性 简单工厂 工厂方法
工厂类数量 1个工厂类 多个工厂类
创建逻辑 集中在一个工厂类 分散在各个具体工厂类
扩展性 修改工厂类 新增工厂类
符合开闭原则
复杂度 简单 较复杂

使用建议

  • 产品种类少且固定:使用简单工厂
  • 产品种类多且可能增加:使用工厂方法模式
  • 需要遵循开闭原则:使用工厂方法模式
  • 创建逻辑复杂:使用工厂方法模式,将创建逻辑分散到各个工厂类中

注意事项

⚠️ 工厂方法模式虽然很好,但不要滥用:

  • 如果产品种类很少(1-2个),直接使用new可能更简单
  • 如果创建逻辑很简单,可以考虑使用简单工厂
  • 工厂方法模式会增加类的数量,要权衡利弊
相关推荐
szm022510 小时前
设计模式-
设计模式
砍光二叉树10 小时前
【设计模式】创建型-抽象工厂模式
设计模式·抽象工厂模式
砍光二叉树11 小时前
【设计模式】创建型-工厂方法模式
设计模式·工厂方法模式
我爱学习_zwj12 小时前
设计模式-2(单例模式与原型模式)
前端·javascript·设计模式
砍光二叉树12 小时前
【设计模式】创建型-单例模式
单例模式·设计模式
我爱学习_zwj12 小时前
设计模式-3(装饰器模式)
前端·设计模式·装饰器模式
文心快码BaiduComate1 天前
Comate内置模型已支持 MiniMax-M2.7!
设计模式·程序员·前端框架
console.log('npc')1 天前
Cursor,Trae,Claude Code如何协作生产出一套前后台app?
前端·人工智能·react.js·设计模式·ai·langchain·ai编程
czxyvX1 天前
C++ - 基于多设计模式下的同步&异步日志系统
c++·设计模式
蒸蒸yyyyzwd1 天前
设计模式之美学习笔记
笔记·学习·设计模式