导读:本期聚焦于广州程序员创作的《C++工厂方法模式怎么应用 抽象基类与具体产品实现方案》,敬请观看详情。工厂方法是C++设计模式里最经典的一种创建型模式,核心思路是把对象的实例化过程延迟到子类,由子类决定到底创建哪一种具体产品。不少人在写多态代码时习惯直接new一个具体类,结果上层逻辑和底层实现耦合死了,后期换实现就要大改代码。这篇文章围绕抽象基类如何定义产品接口、具体产品类怎么落地、工厂类如何组织继承结构这几个关键点展开,给出完整的可编译示例代码,同时对比简单工厂、工厂方法和抽象工厂的适用场景,分析常见的手写误区比如忘记虚析构函数、基类指针内存泄漏等问题,帮你把这套模式真正用在自己的项目里。

在C++项目里,当你发现上层业务代码到处出现new ConcreteProduct这样的语句时,基本可以断定代码耦合已经出问题了:一旦产品类型增加或者实现方式变更,所有调用点都要跟着改。工厂方法模式就是解决这个问题的经典方案,它通过定义一个创建对象的接口,把真正的实例化动作交给子类完成,让对象创建过程与使用过程彻底解耦。本文从抽象基类的设计入手,一步步给出完整的C++实现方案。

C++工厂方法模式怎么应用 抽象基类与具体产品实现方案

工厂方法模式的核心结构

工厂方法模式包含四个角色:抽象产品、具体产品、抽象工厂和具体工厂。抽象产品通常是一个包含纯虚函数的基类,它只声明"能做什么",不关心"怎么做";具体产品继承抽象产品并实现全部接口;抽象工厂声明一个返回抽象产品指针的工厂方法;具体工厂则重写这个方法,返回对应具体产品的实例。

这种结构的关键在于依赖方向的转变。上层模块只依赖抽象工厂和抽象产品两个接口,完全不知道具体产品的存在。当需要更换产品实现时,只需要替换具体工厂,上层代码一行都不用动。这就是所谓的设计原则:"依赖于抽象,而不依赖于具体实现"。

下面是标准的类结构示意代码:

// 抽象产品
class Product {
public:
    virtual ~Product() = default;
    virtual void use() = 0;
};

// 具体产品A
class ConcreteProductA : public Product {
public:
    void use() override { /* A的实现 */ }
};

// 抽象工厂
class Factory {
public:
    virtual ~Factory() = default;
    virtual Product* createProduct() = 0;
};

// 具体工厂A
class ConcreteFactoryA : public Factory {
public:
    Product* createProduct() override {
        return new ConcreteProductA();
    }
};

完整实现方案:智能指针管理对象生命周期

裸指针在C++里容易造成内存泄漏,尤其是上层拿到产品指针后忘记释放的情况非常常见。现代C++推荐工厂方法返回std::unique_ptr,明确所有权归属,调用方用完自动释放,安全性和可读性都大幅提升。

另一个必须重视的细节是虚析构函数。抽象产品基类必须声明virtual ~Product() = default;,否则通过基类指针delete派生类对象属于未定义行为,析构函数不会被正确调用,资源就会泄漏。这是手写工厂模式时最容易踩的坑之一。

下面给一个完整的可编译示例,模拟日志记录器的创建场景:

#include <iostream>
#include <memory>
#include <string>

// 抽象产品:日志记录器
class Logger {
public:
    virtual ~Logger() = default;
    virtual void log(const std::string& msg) = 0;
};

// 具体产品:控制台记录器
class ConsoleLogger : public Logger {
public:
    void log(const std::string& msg) override {
        std::cout << "[Console] " << msg << std::endl;
    }
};

// 具体产品:文件记录器
class FileLogger : public Logger {
public:
    void log(const std::string& msg) override {
        // 实际项目中写入文件,这里简化输出
        std::cout << "[File] " << msg << std::endl;
    }
};

// 抽象工厂
class LoggerFactory {
public:
    virtual ~LoggerFactory() = default;
    virtual std::unique_ptr<Logger> createLogger() = 0;
};

// 具体工厂
class ConsoleLoggerFactory : public LoggerFactory {
public:
    std::unique_ptr<Logger> createLogger() override {
        return std::make_unique<ConsoleLogger>();
    }
};

class FileLoggerFactory : public LoggerFactory {
public:
    std::unique_ptr<Logger> createLogger() override {
        return std::make_unique<FileLogger>();
    }
};

int main() {
    std::unique_ptr<LoggerFactory> factory = std::make_unique<FileLoggerFactory>();
    auto logger = factory->createLogger();
    logger->log("服务启动成功");
    return 0;
}

运行后输出[File] 服务启动成功。注意main函数里上层代码只接触LoggerFactoryLogger两个抽象类型,把FileLoggerFactory换成ConsoleLoggerFactory就能切换实现,完全不影响业务逻辑。

简单工厂、工厂方法与抽象工厂如何选择

简单工厂不是标准GoF模式,它用一个静态函数加switch分支来创建对象,写法简单但违反开闭原则:每新增一种产品都要修改工厂函数的判断逻辑。它适合产品种类少且稳定的场景,比如内部小工具代码。

工厂方法每新增一种产品只需添加一对新的具体产品和具体工厂类,完全符合开闭原则,代价是类的数量膨胀。如果你的产品只有一个维度变化,比如上面的日志器只区分输出介质,用工厂方法就够了。

抽象工厂则用于产品族场景,即产品存在多个维度的组合变化,比如界面库中Windows风格的按钮加滚动条、Linux风格的按钮加滚动条。三种模式的对比可以归纳如下:

模式产品维度开闭原则类数量
简单工厂单一产品,分支判断不满足
工厂方法单一产品类型,子类决定满足中等
抽象工厂多产品组成的族族内满足

常见误区与进阶技巧

第一个误区是工厂方法返回值用裸指针却不约定所有权,团队里多人使用时几乎必然出现重复释放或者泄漏。规范做法是统一返回std::unique_ptr,需要共享所有权时再改成std::shared_ptr

第二个误区是过度设计。如果产品类型就两三种且几乎不会扩展,硬套工厂方法反而增加复杂度,直接构造更清晰。设计模式的价值在于应对变化,没有变化就没有必要引入额外抽象层。

进阶技巧方面,可以结合模板实现静态工厂,减少类膨胀:

template <typename T>
class GenericFactory : public Factory {
public:
    std::unique_ptr<Product> createProduct() override {
        return std::make_unique<T>();
    }
};

// 使用方式,无需为每个产品单独写工厂类
GenericFactory<ConcreteProductA> factoryA;

还可以注册一个全局的工厂注册表,用字符串键映射到创建函数,实现运行时按配置创建产品,这在插件式架构中非常实用。无论采用哪种变体,记住核心不变:抽象基类定义契约,具体产品负责实现,工厂负责把两者连接起来,而上层代码永远只面向抽象编程。

C++工厂方法模式抽象基类具体产品修改时间:2026-09-04 01:50:40

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260904/49939.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。