Menu
CoddyTech

工厂模式

本课属于 Coddy C 学习旅程的“面向对象编程”单元。第 55 课,共 61 课。

工厂模式将对象的创建集中到一个函数中。你不必在程序各处散布 malloc 和初始化代码,而是调用一个函数,由它决定创建什么,并返回一个可直接使用的对象。

这种模式与多态结合时尤其强大。工厂可以通过一个通用的基类指针返回不同的具体类型,从而对调用者隐藏创建细节。调用者只需请求“一个形状”,工厂就会决定创建圆形、矩形或其他形状。

下面是一个典型的工厂实现:

typedef enum {
    SHAPE_CIRCLE,
    SHAPE_RECTANGLE
} ShapeType;

Shape* create_shape(ShapeType type) {
    switch (type) {
        case SHAPE_CIRCLE:
            return (Shape*)create_circle(5.0);
        case SHAPE_RECTANGLE:
            return (Shape*)create_rectangle(4.0, 3.0);
        default:
            return NULL;
    }
}

工厂接收一个标识符(通常是枚举),并使用 switch 语句来确定要调用哪个构造函数。无论实际创建的类型是什么,它都会返回一个 Shape*。调用方不需要知道 Circle 或 Rectangle。它只需使用基类型即可:

Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s);  // 多态调用
free_shape(s);

这种模式让添加新类型变得简单:只需添加一个新的枚举值,并在工厂中添加一个新的 case。其余代码保持不变。

challenge icon

挑战

简单

让我们来构建一个宠物工厂:一个通过单个工厂函数创建不同类型宠物的系统。你不必把创建逻辑分散在代码各处,而是将其集中在一个地方,根据输入标识符决定创建哪种宠物。

你将把代码组织在三个文件中:

  • pet.h:定义一个 PetType 枚举,包含 PET_DOG、PET_CAT 和 PET_BIRD 这些值。创建一个基础 Pet 结构体,其中包含一个用于 speak 的函数指针(该函数接收一个 const Pet*,且不返回任何值)。声明工厂函数 create_pet,它接收一个 PetType 并返回一个 Pet*,此外还要声明用于清理的 free_pet 函数。
  • pet.c:定义三个具体的宠物结构体:Dog、Cat 和 Bird,每个结构体都将 Pet 作为第一个成员嵌入其中。为每种类型实现一个说话函数:
    • 狗打印:Woof!
    • 猫打印:Meow!
    • 鸟打印:Tweet!
    为每种宠物类型创建构造函数,分配内存并设置相应的说话函数。然后实现 create_pet 工厂函数:对 PetType 使用 switch 语句,调用正确的构造函数,并将结果作为 Pet* 返回。对于无效类型,返回 NULL。实现 free_pet,释放已分配的内存。
  • main.c:读取一个表示宠物类型的整数(0 表示狗,1 表示猫,2 表示鸟)。使用工厂创建相应的宠物,通过基础 Pet* 指针以多态方式调用它的 speak 函数,然后释放宠物。

程序会接收一个输入:一个表示要创建哪种宠物的整数。

输入为 0 时的输出示例:

Woof!

输入为 1 时的输出示例:

Meow!

输入为 2 时的输出示例:

Tweet!

工厂模式的优点在于,main.c 不需要了解 Dog、Cat 或 Bird 结构体。它只使用基础 Pet 类型。以后添加新的宠物类型时,只需添加一个新的枚举值和工厂中的一个新分支,无需修改任何使用宠物的代码。

亲手试试

#include <stdio.h>
#include "pet.h"

int main(void) {
    int type;
    scanf("%d", &type);
    
    // TODO:使用工厂创建合适的宠物
    // 提示:将 int 转换为 PetType
    
    // TODO:通过 Pet* 指针以多态方式调用 speak 函数
    
    // TODO:释放宠物占用的内存
    
    return 0;
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: C 在线编译器