C++设计模式之创建型模式:抽象工厂模式(Abstract Factory)

以下是针对C++03标准的抽象工厂模式(Abstract Factory)的详细讲解,包含模式原理、C++03适配实现、代码示例及使用说明,适合需要兼容旧标准的开发场景。

一、抽象工厂模式基础(C++03语境)

抽象工厂模式是创建型模式的重要成员,专注于一系列相互关联的产品族创建。在C++03环境中,虽然缺少智能指针和现代语法,但通过原始指针、虚函数和类继承,依然能完整实现其核心功能:

  • 核心目标:提供一个接口,用于创建多个产品族中的产品,且客户端无需知道具体产品的类型。
  • 典型场景:跨平台开发(如Windows/Linux组件)、数据库驱动套件(如MySQL/Oracle连接+命令对象)等需要配套产品的场景。

二、C++03中的核心角色实现

抽象工厂模式包含4个核心角色,在C++03中通过类层次结构实现:

角色 定义与实现要点(C++03)
抽象产品(Abstract Product) 纯虚类,定义某类产品的接口(如按钮、文本框),包含纯虚方法和虚析构函数(避免析构泄漏)。
具体产品(Concrete Product) 继承抽象产品,实现具体功能(如Windows按钮),重写虚函数时无需override关键字。
抽象工厂(Abstract Factory) 纯虚类,声明创建各抽象产品的工厂方法(如createButton()),返回抽象产品指针。
具体工厂(Concrete Factory) 继承抽象工厂,实现工厂方法,通过new创建并返回具体产品指针(需客户端手动管理内存)。

三、完整代码实现(C++03)

以"数据库访问组件"为例,实现支持MySQL和Oracle的"连接"与"命令"产品族:

cpp 复制代码
#include <iostream>
#include <string>

// 1. 抽象产品A:数据库连接
class DBConnection {
public:
    virtual void connect() const = 0;       // 连接数据库
    virtual void disconnect() const = 0;    // 断开连接
    virtual ~DBConnection() {}              // 虚析构函数
};

// 1. 抽象产品B:数据库命令
class DBCommand {
public:
    virtual void execute(const std::string& sql) const = 0;  // 执行SQL
    virtual ~DBCommand() {}
};

// 2. 具体产品A1:MySQL连接
class MySQLConnection : public DBConnection {
public:
    void connect() const {
        std::cout << "MySQL: 连接到数据库服务器" << std::endl;
    }
    void disconnect() const {
        std::cout << "MySQL: 断开数据库连接" << std::endl;
    }
};

// 2. 具体产品B1:MySQL命令
class MySQLCommand : public DBCommand {
public:
    void execute(const std::string& sql) const {
        std::cout << "MySQL: 执行SQL -> " << sql << std::endl;
    }
};

// 2. 具体产品A2:Oracle连接
class OracleConnection : public DBConnection {
public:
    void connect() const {
        std::cout << "Oracle: 连接到数据库服务器" << std::endl;
    }
    void disconnect() const {
        std::cout << "Oracle: 断开数据库连接" << std::endl;
    }
};

// 2. 具体产品B2:Oracle命令
class OracleCommand : public DBCommand {
public:
    void execute(const std::string& sql) const {
        std::cout << "Oracle: 执行SQL -> " << sql << std::endl;
    }
};

// 3. 抽象工厂:数据库组件工厂
class DBFactory {
public:
    virtual DBConnection* createConnection() const = 0;  // 创建连接
    virtual DBCommand* createCommand() const = 0;        // 创建命令
    virtual ~DBFactory() {}
};

// 4. 具体工厂1:MySQL工厂
class MySQLFactory : public DBFactory {
public:
    DBConnection* createConnection() const {
        return new MySQLConnection();  // C++03用new创建,返回原始指针
    }
    DBCommand* createCommand() const {
        return new MySQLCommand();
    }
};

// 4. 具体工厂2:Oracle工厂
class OracleFactory : public DBFactory {
public:
    DBConnection* createConnection() const {
        return new OracleConnection();
    }
    DBCommand* createCommand() const {
        return new OracleCommand();
    }
};

// 客户端:使用数据库组件
class DataAccess {
private:
    DBFactory* factory;
    DBConnection* conn;
    DBCommand* cmd;

public:
    // 构造函数:接收具体工厂
    DataAccess(DBFactory* f) : factory(f), conn(0), cmd(0) {
        conn = factory->createConnection();
        cmd = factory->createCommand();
    }

    // 析构函数:手动释放内存(C++03关键步骤)
    ~DataAccess() {
        delete cmd;
        delete conn;
        // 工厂由外部管理,此处不删除
    }

    // 业务方法:执行数据库操作
    void doOperation() const {
        conn->connect();
        cmd->execute("SELECT * FROM users");
        conn->disconnect();
    }
};

// 演示代码
int main() {
    // 场景1:使用MySQL
    std::cout << "=== MySQL操作 ===" << std::endl;
    MySQLFactory mysqlFactory;
    DataAccess mysqlAccess(&mysqlFactory);
    mysqlAccess.doOperation();

    // 场景2:使用Oracle
    std::cout << "\n=== Oracle操作 ===" << std::endl;
    OracleFactory oracleFactory;
    DataAccess oracleAccess(&oracleFactory);
    oracleAccess.doOperation();

    return 0;
}

四、C++03实现细节说明

  1. 内存管理策略

    • C++03没有智能指针,必须显式使用new创建对象,并用delete释放(如DataAccess析构函数中释放conncmd)。
    • 工厂对象建议使用栈分配(如MySQLFactory mysqlFactory),避免动态内存管理复杂度过高。
    • 严格遵循"谁创建谁释放"原则:DataAccess创建产品,因此负责释放;工厂由外部传入,不负责释放。
  2. 多态保障

    • 所有抽象类(如DBConnection)必须定义虚析构函数,否则删除子类对象时可能只调用基类析构函数,导致内存泄漏。
    • 子类重写虚函数时,函数签名(参数、返回值、const属性)必须与基类完全一致(C++03无override检查,需手动保证)。
  3. 产品族兼容性

    • 同一具体工厂创建的产品(如MySQLFactoryMySQLConnectionMySQLCommand)天然兼容,确保数据库操作正常协同。
    • 切换数据库类型时,只需替换具体工厂(如OracleFactory),客户端代码(DataAccess)无需修改,符合开闭原则。

五、C++03环境下的优缺点

优点
  • 隔离具体实现 :客户端代码(如DataAccess)仅依赖抽象接口,与MySQLConnection等具体类解耦。
  • 产品族一致性:确保同一工厂的产品可正确协作(如MySQL连接只能搭配MySQL命令)。
  • 便于扩展产品族 :新增数据库(如PostgreSQL)时,只需添加PostgreSQLFactory及对应产品,无需修改现有代码。
缺点(C++03特有)
  • 内存管理复杂 :需手动delete对象,易出现泄漏或二次释放问题(可通过工厂模式+单例模式优化)。
  • 类数量膨胀:每增加一个产品族或产品类型,需新增多个类(如3个数据库×2个产品=6个具体产品类+3个工厂类)。
  • 扩展新产品类型困难 :若需新增产品(如DBReader),需修改抽象工厂接口及所有具体工厂,违反开闭原则。

六、使用建议(C++03项目)

  1. 适合场景:产品族稳定(新增产品族频繁,但新增产品类型少)的项目,如跨平台组件库、数据库驱动套件。
  2. 内存优化 :可将具体工厂设计为单例(避免重复创建),产品对象可考虑对象池模式(减少new/delete开销)。
  3. 与工厂方法结合 :若需新增产品类型(如DBReader),可在具体工厂中用工厂方法模式实现该产品的创建,降低修改成本。

总结

在C++03中实现抽象工厂模式,虽然需要手动管理内存和注意多态细节,但其核心价值------封装产品族创建、保证组件兼容性、简化客户端使用------依然显著。对于需要兼容旧标准且涉及多组关联产品创建的场景,这是一种可靠的设计选择。

相关推荐
Chan162 小时前
【 设计模式 | 创建型模式 建造者模式 】
java·spring boot·设计模式·java-ee·intellij-idea·建造者模式
嵌入式小李.man2 小时前
C++第十篇:const关键字
开发语言·c++
郝学胜-神的一滴2 小时前
基于Linux,看清C++的动态库和静态库
linux·服务器·开发语言·c++·程序人生
澄澈i3 小时前
设计模式学习[19]---单例模式(饿汉式/懒汉式)
学习·单例模式·设计模式
9毫米的幻想3 小时前
【Linux系统】—— 进程切换&&进程优先级&&进程调度
linux·运维·服务器·c++·学习·算法
字节高级特工3 小时前
蓝耘智算与DeepSeekR1:低成本高能AI模型
c++·人工智能·机器学习·计算机视觉
bkspiderx3 小时前
C++设计模式之创建型模式:工厂方法模式(Factory Method)
c++·设计模式·工厂方法模式
ellis19703 小时前
LuaC API开发环境搭建保姆级教程
c++·unity·lua
yujkss3 小时前
23种设计模式之【工厂方法模式】-核心原理与 Java实践
java·设计模式·工厂方法模式