大同市网站建设_网站建设公司_后端开发_seo优化
2025/12/20 20:47:06 网站建设 项目流程

1. 工厂方法模式 (Factory Method)

代码示例

#include <iostream>
#include <string>
using namespace std;// ==========================================
// 1. 抽象产品 (Abstract Product)
// 稳定点:无论日志记录到哪里,写入的接口都是 Log(msg)
// ==========================================
class ILogger {
public:virtual ~ILogger() {}virtual void Log(const string& message) = 0;
};// ==========================================
// 2. 抽象工厂 (Abstract Factory)
// 稳定点:我们总是需要一个“创建者”来生产 logger
// ==========================================
class ILoggerFactory {
public:virtual ~ILoggerFactory() {}// 【工厂方法】:把对象的创建延迟到子类中virtual ILogger* CreateLogger() = 0;
};// ==========================================
// 3. 具体产品 (Concrete Products)
// 变化点:具体的日志记录方式不同
// ==========================================class FileLogger : public ILogger {
public:void Log(const string& message) override {cout << "  [文件日志] 写入磁盘: " << message << endl;}
};class DatabaseLogger : public ILogger {
public:void Log(const string& message) override {cout << "  [数据库日志] 插入 DB 表: " << message << endl;}
};// ==========================================
// 4. 具体工厂 (Concrete Factories)
// 变化点:每个具体产品对应一个具体工厂
// ==========================================// 文件日志工厂:只负责生产 FileLogger
class FileLoggerFactory : public ILoggerFactory {
public:ILogger* CreateLogger() override {// 这里可以包含复杂的初始化逻辑(比如打开文件句柄)return new FileLogger();}
};// 数据库日志工厂:只负责生产 DatabaseLogger
class DatabaseLoggerFactory : public ILoggerFactory {
public:ILogger* CreateLogger() override {// 这里可以包含连接数据库的配置return new DatabaseLogger();}
};// ==========================================
// 客户端代码 (Client)
// ==========================================// 业务逻辑函数:它只依赖抽象工厂和抽象产品
// 它完全不知道 FileLogger 或 DatabaseLogger 的存在
void DoBusinessLogic(ILoggerFactory* factory) {// 1. 通过工厂创建对象 (Create)ILogger* logger = factory->CreateLogger();// 2. 使用对象 (Use)logger->Log("用户登录成功");logger->Log("订单支付完成");delete logger; 
}int main() {cout << "=== 场景 1: 这是一个本地单机版程序 ===" << endl;// 决定使用文件日志ILoggerFactory* factoryA = new FileLoggerFactory();DoBusinessLogic(factoryA);cout << "\n=== 场景 2: 系统升级为企业版 ===" << endl;// 决定使用数据库日志ILoggerFactory* factoryB = new DatabaseLoggerFactory();DoBusinessLogic(factoryB);// 清理工厂delete factoryA;delete factoryB;return 0;
}

1. 定义

  • 原文: 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。
  • 解读:
    • “创建对象的接口”:即 ILoggerFactory::CreateLogger()
    • “延迟到子类”:父类(接口)不知道要创建谁,只有具体的子类(FileLoggerFactory)才知道要 new FileLogger
  • 核心价值: 消除代码中大量的 new ConcreteClass(),从而消除对具体类名的依赖。

2. 解决的问题 (Stable vs. Changing)

这里解决的是“对象创建过程”中的耦合。

  • 稳定点 (Stable):对象的生产接口 & 对象的使用接口
    • “我要一个 Logger”这个需求是不变的。
    • “我要用 Logger 写日志”这个行为是不变的。
  • 变化点 (Changing):具体对象的类型
    • 今天是 FileLogger,明天可能要换成 DatabaseLogger,后天可能是 CloudLogger
    • 对象的初始化过程可能很复杂(比如连库、鉴权),这些逻辑也是变化的。

3. 代码结构 (Code Structure)

标准的“四大金刚”结构:

  1. 抽象产品 (ILogger):定义产品的规范。
  2. 具体产品 (FileLogger):实现具体的功能。
  3. 抽象工厂 (ILoggerFactory):定义“生产产品”的规范。
  4. 具体工厂 (FileLoggerFactory):实现“生产产品”的具体动作(执行 new)。

对比“简单工厂模式” (Simple Factory): 如果用简单工厂,通常会写一个 switch(type) 语句: if (type == "File") return new FileLogger(); else if (type == "DB") return new DatabaseLogger(); 这种写法虽然简单,但如果要加新类型,就必须修改这个 switch 语句,违反了开闭原则。

4. 符合哪些设计原则?

  • A. 依赖倒置原则 (DIP) —— 极其重要
    • 客户端(DoBusinessLogic不依赖 FileLoggerDatabaseLogger
    • 客户端只依赖 ILoggerILoggerFactory
    • 这就是所谓的“面向接口编程”。
  • B. 开闭原则 (OCP)
    • 对扩展开放: 如果要加一个“网络日志”,只需要新建文件,写一个 NetworkLoggerNetworkLoggerFactory
    • 对修改关闭: 你不需要修改 ILoggerFactory 接口,也不需要修改 DoBusinessLogic 函数,更不需要修改现有的 FileLogger 类。
  • C. 单一职责原则 (SRP)
    • CreateLogger() 的逻辑被拆分到了各个具体的 Factory 中。
    • FileLoggerFactory 只负责创建文件日志对象,不负责其他的,代码逻辑清晰。

5. 如何扩展?

这是工厂方法模式最优雅的地方。假设我们需要增加一个 “云端日志 (CloudLogger)”

  1. 新建具体产品:

    class CloudLogger : public ILogger {void Log(const string& msg) override { cout << "上传到阿里云: " << msg << endl; }
    };
    
  2. 新建具体工厂:

    class CloudLoggerFactory : public ILoggerFactory {ILogger* CreateLogger() override { return new CloudLogger(); }
    };
    
  3. 客户端使用:

    // 原有的 DoBusinessLogic 完全不用改!
    ILoggerFactory* cloudFactory = new CloudLoggerFactory();
    DoBusinessLogic(cloudFactory);
    

💡 深思考:为什么不直接 new?

很多初学者会问:“为什么非要搞个工厂类这么麻烦?我直接在 main 里 new FileLogger 不行吗?”

回答: 如果你的程序很小,只有 main 函数里用了一次,那确实可以直接 new。 但是,如果你的 FileLogger 需要在系统中的 100 个地方 被创建,而且它的初始化构造函数很复杂(比如要读取配置文件、设置缓冲区大小)。

  • 直接 New: 当你想把 FileLogger 换成 DbLogger 时,你需要去这 100 个地方修改代码。
  • 用工厂: 你只需要把那个传递给系统的 factory 指针换掉(只改 1 处),整个系统 100 个地方生产出来的对象就瞬间全部变了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询