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

工厂方法模式 (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可能更简单
  • 如果创建逻辑很简单,可以考虑使用简单工厂
  • 工厂方法模式会增加类的数量,要权衡利弊
相关推荐
把csdn当日记本的菜鸡2 小时前
Java设计模式简单入门
java·开发语言·设计模式
老蒋每日coding2 小时前
AI Agent 设计模式系列(十一)—— 目标设定和监控模式
人工智能·设计模式·langchain
蔺太微3 小时前
外观模式(Facade Pattern)
设计模式·外观模式
进击的小头3 小时前
C语言实现设计模式的核心基石
c语言·开发语言·设计模式
Engineer邓祥浩3 小时前
设计模式学习(15) 23-13 模版方法模式
java·学习·设计模式
茶本无香3 小时前
设计模式之四:建造者模式(Builder Pattern)详解
java·设计模式·建造者模式
山风wind5 小时前
设计模式-访问者模式详解
python·设计模式·访问者模式
Yu_Lijing5 小时前
基于C++的《Head First设计模式》笔记——组合模式
c++·笔记·设计模式·组合模式
Engineer邓祥浩5 小时前
设计模式学习(17) 23-15 访问者模式
学习·设计模式·访问者模式