C++ 工厂模式

开闭原则

开闭原则是面向对象设计SOLID原则中的第二个原则,由Bertrand Meyer在1988年提出

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

核心思想是:

  • 对扩展开放

    • 允许在不修改现有代码的情况下,添加新的功能
    • 通过继承、组合、接口等方式扩展行为
  • 对修改关闭

    • 现有代码应该保持稳定,不被频繁修改
    • 修改现有代码可能引入新的错误

工厂模式

通过 ai 搜索可知:工厂模式是创建型设计模式的一种,它通过定义一个创建对象的接口,让子类决定实例化哪一个类,使一个类的实例化延迟到其子类。在C++中,工厂模式主要分为三种:简单工厂模式(Simple Factory)、工厂方法模式(Factory Method)和抽象工厂模式(Abstract Factory)。

简单工厂模式

简单工厂模式通过一个工厂类来决定创建哪种产品类的实例。用户只需要传递一个参数给工厂类,不需要关心创建细节,只需关心产品的接口。但是,每次增加一个产品时,都需要增加一个具体类和对象实现工厂,这会使得系统中类的个数成倍增加,增加了系统的复杂度。

实例代码如下

// 产品接口
class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() {}
};

// 具体产品
class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Rectangle" << std::endl;
    }
};

// 简单工厂
class ShapeFactory {
public:
    static std::unique_ptr<Shape> createShape(const std::string& type) {
        if (type == "circle") {
            return std::make_unique<Circle>();
        } else if (type == "rectangle") {
            return std::make_unique<Rectangle>();
        }
        return nullptr;
    }
};

// 使用示例
int main() {
    auto shape1 = ShapeFactory::createShape("circle");
    auto shape2 = ShapeFactory::createShape("rectangle");
    
    if (shape1) shape1->draw();
    if (shape2) shape2->draw();
    
    return 0;
}

Shape 为抽象产品类,通过虚函数定义产品的公共接口(

公共接口简单讲就是,通过抽象基类,所派生的产品类有相同的函数名,功能一致,但是函数实现的具体细节不完全一样

Circle 和 Rectangle 为派生出来的具体产品类,对 draw 函数有各自不一样的实现方式。为了通过参数,控制具体需要实现哪种产品类,我们可以定义简单工厂 ShapeFactory,通过 string 变量,选择需要实例化的产品类。

可以看到,抽象基类的指针也可以指向具体产品类,这样可以最大程度地节省代码改写量。

工厂方法

工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。这样的模式解决了简单工厂模式中的问题,即无法对修改关闭。

// 产品接口
class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() {}
};

// 具体产品
class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Rectangle" << std::endl;
    }
};

// 工厂方法
class ShapeFactory {
public:
	virtual std::unique_ptr<Shape> createShape() = 0;
	virtual ~ShapeFactory() = default; // 虚析构函数
};

class CircleFactory : public ShapeFactory{
public:
	std::unique_ptr<Shape> createShape() override {
		return std::make_unique<Circle>();
	}
};

class RectangleFactory : public ShapeFactory{
public:
	std::unique_ptr<Shape> createShape() override {
		return std::make_unique<Rectangle>();
	}
};

// 使用者
void drawFunc(ShapeFactory& factory){
	auto shapeDraw = factory.createShape();
	shapeDraw.draw();
};

int main(){
	CircleFactory temp;
	drawFunc(temp);
	return 0;
}

工厂方法为每个具体产品创建了独立的工厂:CircleFactory,RectangleFactory,当添加了新的产品时,也需要添加对于产品的工厂。以下是简单工厂与工厂方法的特点分析:

// 简单工厂 - 一个类负责所有产品的创建
// LoggerFactory 需要知道所有Logger的创建细节
// 职责过多,随着产品增多会变得臃肿

// 工厂方法 - 每个工厂只负责一种产品的创建
// FileLoggerCreator 只关心 FileLogger 的创建
// ConsoleLoggerCreator 只关心 ConsoleLogger 的创建
// 职责清晰,符合单一职责原则

// 如果有20种产品:
// 简单工厂:1个工厂 + 20个产品 = 21个类
// 工厂方法:1个抽象工厂 + 20个具体工厂 + 20个产品 = 41个类
// 简单工厂减少了约50%的类数量

// 简单工厂:1个工厂类 + n个产品类
// 工厂方法:1个抽象工厂 + n个具体工厂 + n个产品类
// 工厂方法多了n个具体工厂类

适合简单工厂:
// 1. 产品种类少且固定
// 2. 不需要运行时动态扩展
// 3. 追求代码简洁性
// 4. 团队规模小,变更不频繁

适合工厂方法:
// 1. 产品类型可能频繁扩展
// 2. 不同产品需要不同的初始化逻辑
// 3. 框架设计,需要让子类决定创建什么
// 4. 需要支持多种配置的产品创建

抽象工厂模式

抽象工厂模式本质上是:

  1. 多个工厂方法模式的组合:每个createXxx()方法都是一个工厂方法
  2. 更高层次的抽象:关注产品族而非单个产品
  3. 更强的约束保证:确保创建的所有产品都是兼容的

这种层次关系体现了面向对象设计的核心思想:从简单到复杂,通过组合构建更强大的抽象

  • 只有一个产品需要创建(工厂方法)
// 只关心创建按钮
class ButtonFactory {
public:
    virtual Button* createButton() = 0;
};
  • 需要创建多个相关产品(演变为抽象工厂)
// 需要创建一整套UI组件
class UIFactory {
public:
    virtual Button* createButton() = 0;
    virtual TextBox* createTextBox() = 0;      // 新增需求
    virtual CheckBox* createCheckBox() = 0;    // 新增需求
};

参考资料


[1] deepseek.



最后更新于 2025年12月21日 --- 最初发表于 2025年12月21日
原创作者:LitBro
关于作者:c++ 让人秃头
本文链接: [https://www.cnblogs.com/LitBro/p/19380077]
版权声明:本文采用 BY-NC-SA协议,转载或引用请注明出处!
关于后续:碍于学业不精,如有描述不当,还请见谅并非常感谢指出

posted @ 2025-12-21 22:33  LitBro  阅读(2)  评论(0)    收藏  举报