设计模式之工厂方法

1 核心定义

工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪个类。工厂方法让类的实例化推迟到子类进行,实现了"对象创建"与"对象使用"的分离。

2 核心思想

1 封装对象创建:将对象的创建过程封装在工厂方法中

2 延迟实例化:将具体类的实例化延迟到子类

3 依赖倒置:依赖抽象工厂,而不是具体类

4 可扩展性:新增产品时,只需扩展工厂,无需修改客户端代码

3 结构组成

Product(产品接口):定义产品的接口

ConcreteProduct(具体产品):实现产品接口的具体类

Creator(创建者抽象类):声明工厂方法,返回Product对象

ConcreteCreator(具体创建者):重写工厂方法,返回具体产品

4 应用场景举例

以日志记录器系统为例:

1 多种日志记录方式:文件日志、数据库日志、控制台日志

2 每种日志记录方式有不同的初始化方式和配置要求

3 客户端需要根据配置或条件选择不同的日志记录器

4 日志记录器的创建过程可能很复杂,包括配置加载、连接建立等

5 UML

6 c++ 代码实现

cpp 复制代码
#include <iostream>
#include <string>
#include <memory>
#include <fstream>
#include <ctime>
using namespace std;

// 产品接口:日志记录器
class Logger {
public:
    virtual ~Logger() = default;
    virtual void log(const string& message) = 0;
    virtual void error(const string& message) = 0;
    virtual void warn(const string& message) = 0;
};

// 具体产品:文件日志记录器
class FileLogger : public Logger {
private:
    string filename;
    ofstream logFile;
    
    string getCurrentTime() {
        time_t now = time(nullptr);
        return ctime(&now);
    }
    
public:
    FileLogger(const string& file) : filename(file) {
        logFile.open(filename, ios::app);
        if (!logFile.is_open()) {
            throw runtime_error("无法打开日志文件: " + filename);
        }
        log("【文件日志系统启动】");
    }
    
    ~FileLogger() {
        if (logFile.is_open()) {
            log("【文件日志系统关闭】");
            logFile.close();
        }
    }
    
    void log(const string& message) override {
        logFile << "[INFO][" << getCurrentTime() << "] " << message << endl;
        logFile.flush();
    }
    
    void error(const string& message) override {
        logFile << "[ERROR][" << getCurrentTime() << "] " << message << endl;
        logFile.flush();
    }
    
    void warn(const string& message) override {
        logFile << "[WARN][" << getCurrentTime() << "] " << message << endl;
        logFile.flush();
    }
};

// 具体产品:数据库日志记录器
class DatabaseLogger : public Logger {
private:
    string connectionString;
    
    void connectToDatabase() {
        cout << "连接到数据库: " << connectionString << endl;
        // 模拟数据库连接
    }
    
    void disconnectFromDatabase() {
        cout << "断开数据库连接" << endl;
    }
    
public:
    DatabaseLogger(const string& connStr) : connectionString(connStr) {
        connectToDatabase();
        log("【数据库日志系统启动】");
    }
    
    ~DatabaseLogger() {
        log("【数据库日志系统关闭】");
        disconnectFromDatabase();
    }
    
    void log(const string& message) override {
        cout << "[数据库日志] " << message << endl;
        // 实际项目这里会执行SQL插入操作
    }
    
    void error(const string& message) override {
        cout << "[数据库日志][ERROR] " << message << endl;
    }
    
    void warn(const string& message) override {
        cout << "[数据库日志][WARN] " << message << endl;
    }
};

// 具体产品:控制台日志记录器
class ConsoleLogger : public Logger {
private:
    bool colorEnabled;
    
    void setConsoleColor(const string& color) {
        // 设置控制台颜色的代码
        if (color == "red") cout << "\033[31m";
        else if (color == "yellow") cout << "\033[33m";
        else if (color == "green") cout << "\033[32m";
    }
    
    void resetConsoleColor() {
        cout << "\033[0m";
    }
    
public:
    ConsoleLogger(bool enableColor = true) : colorEnabled(enableColor) {
        cout << "控制台日志系统启动" << endl;
    }
    
    void log(const string& message) override {
        if (colorEnabled) setConsoleColor("green");
        cout << "[INFO] " << message << endl;
        if (colorEnabled) resetConsoleColor();
    }
    
    void error(const string& message) override {
        if (colorEnabled) setConsoleColor("red");
        cerr << "[ERROR] " << message << endl;
        if (colorEnabled) resetConsoleColor();
    }
    
    void warn(const string& message) override {
        if (colorEnabled) setConsoleColor("yellow");
        cout << "[WARN] " << message << endl;
        if (colorEnabled) resetConsoleColor();
    }
};

// 抽象创建者:日志记录器工厂
class LoggerFactory {
public:
    virtual ~LoggerFactory() = default;
    
    // 工厂方法
    virtual Logger* createLogger() = 0;
    
    // 可以在工厂中添加一些公共的创建后处理逻辑
    Logger* getLogger() {
        Logger* logger = createLogger();
        // 可以在这里添加一些通用的初始化代码
        cout << "日志记录器创建成功" << endl;
        return logger;
    }
};

// 具体创建者:文件日志记录器工厂
class FileLoggerFactory : public LoggerFactory {
private:
    string filename;
    
public:
    FileLoggerFactory(const string& file) : filename(file) {}
    
    Logger* createLogger() override {
        return new FileLogger(filename);
    }
};

// 具体创建者:数据库日志记录器工厂
class DatabaseLoggerFactory : public LoggerFactory {
private:
    string connectionString;
    
public:
    DatabaseLoggerFactory(const string& connStr) : connectionString(connStr) {}
    
    Logger* createLogger() override {
        return new DatabaseLogger(connectionString);
    }
};

// 具体创建者:控制台日志记录器工厂
class ConsoleLoggerFactory : public LoggerFactory {
private:
    bool colorEnabled;
    
public:
    ConsoleLoggerFactory(bool enableColor = true) : colorEnabled(enableColor) {}
    
    Logger* createLogger() override {
        return new ConsoleLogger(colorEnabled);
    }
};

// 客户端代码
class Application {
private:
    unique_ptr<Logger> logger;
    
public:
    void initialize(const string& logType) {
        LoggerFactory* factory = nullptr;
        
        // 根据配置选择具体的工厂
        if (logType == "file") {
            factory = new FileLoggerFactory("app.log");
        } else if (logType == "database") {
            factory = new DatabaseLoggerFactory("localhost:3306/logdb");
        } else if (logType == "console") {
            factory = new ConsoleLoggerFactory(true);
        } else {
            throw runtime_error("不支持的日志类型");
        }
        
        // 通过工厂创建日志记录器
        logger.reset(factory->getLogger());
        delete factory;
    }
    
    void run() {
        if (!logger) {
            cout << "日志系统未初始化" << endl;
            return;
        }
        
        logger->log("应用程序启动");
        logger->warn("这是一个警告信息");
        logger->error("这是一个错误信息");
        logger->log("应用程序运行中...");
    }
};

// 主函数
int main() {
    try {
        cout << "=== 使用文件日志 ===" << endl;
        Application app1;
        app1.initialize("file");
        app1.run();
        cout << endl;
        
        cout << "=== 使用数据库日志 ===" << endl;
        Application app2;
        app2.initialize("database");
        app2.run();
        cout << endl;
        
        cout << "=== 使用控制台日志 ===" << endl;
        Application app3;
        app3.initialize("console");
        app3.run();
        
    } catch (const exception& e) {
        cerr << "错误: " << e.what() << endl;
    }
    
    return 0;
}

7 对比分析与优势总结

7.1 不使用工厂方法模式的坏处

不使用工厂方法模式的坏处

如果不使用工厂方法模式,可能会采用以下几种实现方式:
方式1:直接使用new创建对象

cpp 复制代码
class Application {
private:
    Logger* logger;
    
public:
    void initialize(const string& logType) {
        // 直接在客户端代码中创建具体对象
        if (logType == "file") {
            logger = new FileLogger("app.log");
        } else if (logType == "database") {
            logger = new DatabaseLogger("localhost:3306/logdb");
        } else if (logType == "console") {
            logger = new ConsoleLogger(true);
        }
    }
    
    // ... 其他代码
};

问题:

客户端代码与具体产品类耦合

创建逻辑分散在各个客户端中

添加新的日志类型需要修改所有客户端代码

方式2:使用简单工厂

cpp 复制代码
class SimpleLoggerFactory {
public:
    static Logger* createLogger(const string& type) {
        if (type == "file") {
            return new FileLogger("app.log");
        } else if (type == "database") {
            return new DatabaseLogger("localhost:3306/logdb");
        } else if (type == "console") {
            return new ConsoleLogger(true);
        }
        return nullptr;
    }
};

问题:

工厂类职责过重,包含所有产品的创建逻辑

添加新产品需要修改工厂类,违反开闭原则

无法通过继承来改变创建行为

方式3:使用全局函数或宏

cpp 复制代码
#define CREATE_FILE_LOGGER() new FileLogger("app.log")
#define CREATE_DATABASE_LOGGER() new DatabaseLogger("localhost:3306/logdb")

问题:

缺乏类型安全

调试困难

无法进行面向对象扩展

7.2 使用工厂方法模式的优势

1 解耦:客户端代码与具体产品类解耦

2 可扩展:添加新产品时无需修改现有代码

3 统一创建接口:所有产品都通过统一的工厂方法创建

4 支持复杂创建过程:可以在工厂方法中封装复杂的创建逻辑

5 符合单一职责:创建对象的职责被集中到工厂类中

6 便于测试:可以创建测试专用的工厂类返回mock对象

8 适用场景

客户端不知道它所需要的对象的具体类

工厂类希望由子类指定创建的对象类型

对象的创建过程比较复杂,需要独立封装

需要在不同条件下创建不同的产品实例

需要将对象的创建和使用分离

工厂方法模式通过将对象的创建延迟到子类,很好地解决了对象创建过程中的耦合问题,是创建型设计模式中非常重要的一种。

相关推荐
Anurmy3 小时前
设计模式之适配器模式
设计模式·适配器模式
逆境不可逃3 小时前
【从零入门23种设计模式12】结构型之代理模式(Spring AOP + 自定义注解 + 切面的实战)
设计模式·代理模式
电子科技圈3 小时前
IAR扩展嵌入式开发平台,推出面向安全关键型应用的长期支持(LTS)服务
嵌入式硬件·安全·设计模式·软件工程·代码规范·设计规范·代码复审
像少年啦飞驰点、4 小时前
Java策略模式从入门到实战:小白也能看懂的设计模式指南
java·设计模式·策略模式·编程入门·小白教程
程序员Terry4 小时前
别再用 if-else 堆砌代码了!策略模式让你的代码优雅十倍
java·设计模式
JTCC5 小时前
Java 设计模式西游篇 - 第八回:适配器模式通万国 女儿国语言无障碍
python·设计模式·适配器模式
逆境不可逃5 小时前
【从零入门23种设计模式17】行为型之中介者模式
java·leetcode·microsoft·设计模式·职场和发展·中介者模式
Anurmy5 小时前
设计模式之抽象工厂
设计模式
蜜獾云5 小时前
设计模式之原型模式:以自己为原型,自己实现自己的对象拷贝逻辑
java·设计模式·原型模式