工厂模式
本课属于 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。其余代码保持不变。
挑战
简单让我们来构建一个宠物工厂:一个通过单个工厂函数创建不同类型宠物的系统。你不必把创建逻辑分散在代码各处,而是将其集中在一个地方,根据输入标识符决定创建哪种宠物。
你将把代码组织在三个文件中:
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;
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C 在线编译器