设计模式之工厂模式在 C 语言中的应用(含 Linux 内核实例)

文章目录

        • 一、工厂模式的定义与核心价值
        • [二、C 语言实现工厂模式的核心思路](#二、C 语言实现工厂模式的核心思路)
        • [三、 5 个实例](#三、 5 个实例)
          • [实例 1:简单工厂(形状创建)](#实例 1:简单工厂(形状创建))
          • [实例 2:工厂方法(日志器创建)](#实例 2:工厂方法(日志器创建))
          • [实例 3:简单工厂(硬件设备创建)](#实例 3:简单工厂(硬件设备创建))
          • [实例 4:工厂方法(数据库连接创建)](#实例 4:工厂方法(数据库连接创建))
          • [实例 5:内核风格工厂(内存块创建)](#实例 5:内核风格工厂(内存块创建))
        • [四、Linux 内核中的工厂模式应用](#四、Linux 内核中的工厂模式应用)
        • 五、实现注意事项
        • 六、补充说明
一、工厂模式的定义与核心价值

工厂模式(Factory Pattern)是一种创建型设计模式,其核心是通过统一的 "工厂" 接口创建对象,而非直接调用malloc或构造函数。该模式将对象创建逻辑与使用逻辑解耦,隐藏对象创建的细节(如内存分配、初始化步骤),让客户端只需关注对象的使用,无需关心对象如何创建。

存在的意义:当对象创建过程复杂(需多步初始化、依赖外部配置或有多种变体),或需批量创建同类型对象时,直接在客户端创建对象会导致代码冗余、耦合紧密。工厂模式通过集中化的工厂统一管理对象创建,降低客户端与对象实现的耦合,同时便于后续扩展新的对象类型。

解决的问题

  • 客户端直接创建对象导致代码冗余,尤其是对象初始化步骤较多时;
  • 对象类型频繁变化或新增时,需修改大量客户端代码,违反 "开闭原则";
  • 对象创建细节(如内存分配、资源初始化)暴露给客户端,增加使用复杂度和出错风险。
二、C 语言实现工厂模式的核心思路

C 语言通过结构体封装对象与工厂 +函数指针定义创建接口实现模式,核心分为两类:

  1. 简单工厂(Simple Factory):一个工厂负责创建所有类型的对象,通过参数(如类型 ID)区分对象类型,适合对象类型较少且变化不频繁的场景;
  2. 工厂方法(Factory Method):为每种对象类型定义一个专属工厂(继承统一工厂接口),客户端通过对应的工厂创建对象,适合对象类型较多或频繁扩展的场景。

两种模式的核心都是 "工厂负责创建,客户端负责使用",区别在于工厂的粒度和扩展方式。

三、 5 个实例
实例 1:简单工厂(形状创建)

通过一个工厂根据类型参数(圆形 / 矩形)创建不同形状对象,适合对象类型较少的场景。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

// 1. 抽象产品:形状(统一接口)
typedef struct {
    void (*draw)(const struct Shape* self); // 绘制方法
    void (*destroy)(struct Shape* self);   // 销毁方法
    const char* type;                      // 形状类型
} Shape;

// 2. 具体产品1:圆形
typedef struct {
    Shape base; // 继承抽象形状
    float radius; // 圆形特有属性:半径
} Circle;

static void circle_draw(const Shape* self) {
    const Circle* circle = (const Circle*)self;
    printf("Drawing Circle: radius=%.1f\n", circle->radius);
}

static void circle_destroy(Shape* self) {
    free(self);
}

// 具体产品2:矩形
typedef struct {
    Shape base; // 继承抽象形状
    float width;  // 矩形特有属性:宽
    float height; // 矩形特有属性:高
} Rectangle;

static void rect_draw(const Shape* self) {
    const Rectangle* rect = (const Rectangle*)self;
    printf("Drawing Rectangle: width=%.1f, height=%.1f\n", rect->width, rect->height);
}

static void rect_destroy(Shape* self) {
    free(self);
}

// 3. 简单工厂:形状工厂(根据类型创建对象)
typedef enum { SHAPE_CIRCLE, SHAPE_RECTANGLE } ShapeType;

Shape* create_shape(ShapeType type, ...) {
    // 使用可变参数处理不同形状的初始化参数
    va_list args;
    va_start(args, type);

    Shape* shape = NULL;
    switch (type) {
        case SHAPE_CIRCLE: {
            float radius = va_arg(args, double); // 可变参数读取半径(float提升为double)
            Circle* circle = malloc(sizeof(Circle));
            circle->base.type = "Circle";
            circle->base.draw = circle_draw;
            circle->base.destroy = circle_destroy;
            circle->radius = radius;
            shape = (Shape*)circle;
            break;
        }
        case SHAPE_RECTANGLE: {
            float width = va_arg(args, double);
            float height = va_arg(args, double);
            Rectangle* rect = malloc(sizeof(Rectangle));
            rect->base.type = "Rectangle";
            rect->base.draw = rect_draw;
            rect->base.destroy = rect_destroy;
            rect->width = width;
            rect->height = height;
            shape = (Shape*)rect;
            break;
        }
        default:
            printf("Unsupported shape type\n");
            break;
    }

    va_end(args);
    return shape;
}

// 客户端使用:通过工厂创建形状,无需关心具体实现
int main() {
    // 1. 创建圆形(通过工厂+类型参数)
    Shape* circle = create_shape(SHAPE_CIRCLE, 5.0f);
    if (circle) {
        printf("Created %s\n", circle->type);
        circle->draw(circle);
        circle->destroy(circle);
    }

    // 2. 创建矩形(通过工厂+类型参数)
    Shape* rect = create_shape(SHAPE_RECTANGLE, 4.0f, 6.0f);
    if (rect) {
        printf("\nCreated %s\n", rect->type);
        rect->draw(rect);
        rect->destroy(rect);
    }

    return 0;
}

以上代码运行结果为

复制代码
Created Circle
Drawing Circle: radius=5.0

Created Rectangle
Drawing Rectangle: width=4.0, height=6.0

其对应 的UML图例如下

即:简单工厂create_shape通过ShapeType参数区分对象类型,客户端只需传入类型和初始化参数,即可获取完整对象。新增形状(如三角形)只需修改工厂的switch分支,无需修改客户端代码。

实例 2:工厂方法(日志器创建)

为每种日志器(控制台日志 / 文件日志)定义专属工厂,客户端通过对应工厂创建对象,适合频繁扩展对象类型的场景。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

// 1. 抽象产品:日志器(统一接口)
typedef struct {
    void (*log)(const struct Logger* self, const char* level, const char* msg);
    void (*destroy)(struct Logger* self);
    const char* type;
} Logger;

// 2. 抽象工厂:日志器工厂(统一创建接口)
typedef struct {
    Logger* (*create_logger)(struct LoggerFactory* self);
    void (*destroy_factory)(struct LoggerFactory* self);
} LoggerFactory;

// 3. 具体产品1:控制台日志器
typedef struct {
    Logger base;
} ConsoleLogger;

static void console_log(const Logger* self, const char* level, const char* msg) {
    (void)self;
    char time_buf[20];
    time_t t = time(NULL);
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", localtime(&t));
    printf("[%s] [%s] %s\n", time_buf, level, msg);
}

static void console_destroy(Logger* self) {
    free(self);
}

// 具体工厂1:控制台日志器工厂
typedef struct {
    LoggerFactory base;
} ConsoleLoggerFactory;

static Logger* console_create_logger(LoggerFactory* self) {
    (void)self;
    ConsoleLogger* logger = malloc(sizeof(ConsoleLogger));
    logger->base.type = "ConsoleLogger";
    logger->base.log = console_log;
    logger->base.destroy = console_destroy;
    return (Logger*)logger;
}

static void console_destroy_factory(LoggerFactory* self) {
    free(self);
}

// 初始化控制台日志工厂
LoggerFactory* create_console_log_factory() {
    ConsoleLoggerFactory* factory = malloc(sizeof(ConsoleLoggerFactory));
    factory->base.create_logger = console_create_logger;
    factory->base.destroy_factory = console_destroy_factory;
    return (LoggerFactory*)factory;
}

// 具体产品2:文件日志器
typedef struct {
    Logger base;
    const char* filename; // 文件日志特有属性:日志文件名
} FileLogger;

static void file_log(const Logger* self, const char* level, const char* msg) {
    const FileLogger* file_logger = (const FileLogger*)self;
    FILE* f = fopen(file_logger->filename, "a");
    if (!f) return;

    char time_buf[20];
    time_t t = time(NULL);
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", localtime(&t));
    fprintf(f, "[%s] [%s] %s\n", time_buf, level, msg);
    fclose(f);

    printf("Logged to %s: [%s] %s\n", file_logger->filename, level, msg);
}

static void file_destroy(Logger* self) {
    free(self);
}

// 具体工厂2:文件日志器工厂(需传入文件名参数)
typedef struct {
    LoggerFactory base;
    const char* filename; // 工厂持有文件日志的配置参数
} FileLoggerFactory;

static Logger* file_create_logger(LoggerFactory* self) {
    FileLoggerFactory* file_factory = (FileLoggerFactory*)self;
    FileLogger* logger = malloc(sizeof(FileLogger));
    logger->base.type = "FileLogger";
    logger->base.log = file_log;
    logger->base.destroy = file_destroy;
    logger->filename = file_factory->filename; // 传递配置参数到产品
    return (Logger*)logger;
}

static void file_destroy_factory(LoggerFactory* self) {
    free(self);
}

// 初始化文件日志工厂(传入文件名)
LoggerFactory* create_file_log_factory(const char* filename) {
    FileLoggerFactory* factory = malloc(sizeof(FileLoggerFactory));
    factory->filename = filename;
    factory->base.create_logger = file_create_logger;
    factory->base.destroy_factory = file_destroy_factory;
    return (LoggerFactory*)factory;
}

// 客户端使用:通过专属工厂创建日志器,扩展新日志器无需修改旧代码
int main() {
    // 1. 使用控制台日志工厂
    LoggerFactory* console_factory = create_console_log_factory();
    Logger* console_logger = console_factory->create_logger(console_factory);
    printf("=== Using %s ===\n", console_logger->type);
    console_logger->log(console_logger, "INFO", "Program started");
    console_logger->destroy(console_logger);
    console_factory->destroy_factory(console_factory);

    // 2. 使用文件日志工厂
    LoggerFactory* file_factory = create_file_log_factory("app.log");
    Logger* file_logger = file_factory->create_logger(file_factory);
    printf("\n=== Using %s ===\n", file_logger->type);
    file_logger->log(file_logger, "ERROR", "Config load failed");
    file_logger->destroy(file_logger);
    file_factory->destroy_factory(file_factory);

    return 0;
}

以上代码运行结果为

复制代码
=== Using ConsoleLogger ===
[2025-10-26 16:16:29] [INFO] Program started

=== Using FileLogger ===
Logged to app.log: [ERROR] Config load failed

其对应 的UML图例如下

即:工厂方法模式为每种日志器定义专属工厂,新增日志器(如网络日志)只需添加 "网络日志产品 + 网络日志工厂",无需修改现有工厂和客户端代码,完全符合 "开闭原则"。

实例 3:简单工厂(硬件设备创建)

模拟嵌入式系统中通过工厂创建不同硬件设备(UART/SPI),工厂负责设备的初始化配置,客户端直接使用设备功能。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>

// 1. 抽象产品:硬件设备(统一接口)
typedef struct {
    bool (*init)(struct Device* self, uint32_t base_addr); // 设备初始化
    void (*send)(struct Device* self, const uint8_t* data, size_t len); // 发送数据
    void (*destroy)(struct Device* self);
    const char* type;
    uint32_t base_addr; // 设备基地址(通用属性)
} Device;

// 2. 具体产品1:UART设备
typedef struct {
    Device base;
    uint32_t baud_rate; // UART特有属性:波特率
} UARTDevice;

static bool uart_init(Device* self, uint32_t base_addr) {
    UARTDevice* uart = (UARTDevice*)self;
    uart->base.base_addr = base_addr;
    uart->baud_rate = 115200; // 默认波特率
    printf("UART initialized at 0x%08X, baud rate: %d\n", base_addr, uart->baud_rate);
    return true;
}

static void uart_send(Device* self, const uint8_t* data, size_t len) {
    UARTDevice* uart = (UARTDevice*)self;
    printf("UART sending %zu bytes: ", len);
    for (size_t i = 0; i < len; i++) {
        printf("%02X ", data[i]);
    }
    printf("\n");
}

static void uart_destroy(Device* self) {
    free(self);
}

// 具体产品2:SPI设备
typedef struct {
    Device base;
    uint32_t clk_freq; // SPI特有属性:时钟频率
} SPIDevice;

static bool spi_init(Device* self, uint32_t base_addr) {
    SPIDevice* spi = (SPIDevice*)self;
    spi->base.base_addr = base_addr;
    spi->clk_freq = 1000000; // 默认1MHz
    printf("SPI initialized at 0x%08X, clock freq: %d Hz\n", base_addr, spi->clk_freq);
    return true;
}

static void spi_send(Device* self, const uint8_t* data, size_t len) {
    SPIDevice* spi = (SPIDevice*)self;
    printf("SPI sending %zu bytes: ", len);
    for (size_t i = 0; i < len; i++) {
        printf("%02X ", data[i]);
    }
    printf("\n");
}

static void spi_destroy(Device* self) {
    free(self);
}

// 3. 简单工厂:设备工厂(根据类型创建硬件设备)
typedef enum { DEVICE_UART, DEVICE_SPI } DeviceType;

Device* create_device(DeviceType type) {
    Device* device = NULL;
    switch (type) {
        case DEVICE_UART: {
            UARTDevice* uart = malloc(sizeof(UARTDevice));
            uart->base.type = "UART";
            uart->base.init = uart_init;
            uart->base.send = uart_send;
            uart->base.destroy = uart_destroy;
            device = (Device*)uart;
            break;
        }
        case DEVICE_SPI: {
            SPIDevice* spi = malloc(sizeof(SPIDevice));
            spi->base.type = "SPI";
            spi->base.init = spi_init;
            spi->base.send = spi_send;
            spi->base.destroy = spi_destroy;
            device = (Device*)spi;
            break;
        }
        default:
            printf("Unsupported device type\n");
            break;
    }
    return device;
}

// 客户端使用:通过工厂创建设备,统一调用初始化和发送接口
int main() {
    uint8_t data[] = {0xAA, 0xBB, 0xCC};
    size_t data_len = sizeof(data)/sizeof(data[0]);

    // 1. 创建并使用UART设备
    Device* uart = create_device(DEVICE_UART);
    if (uart) {
        printf("=== Using %s Device ===\n", uart->type);
        uart->init(uart, 0x10000000); // 初始化UART(基地址0x10000000)
        uart->send(uart, data, data_len);
        uart->destroy(uart);
    }

    // 2. 创建并使用SPI设备
    Device* spi = create_device(DEVICE_SPI);
    if (spi) {
        printf("\n=== Using %s Device ===\n", spi->type);
        spi->init(spi, 0x10001000); // 初始化SPI(基地址0x10001000)
        spi->send(spi, data, data_len);
        spi->destroy(spi);
    }

    return 0;
}

以上代码运行结果为

复制代码
=== Using UART Device ===
UART initialized at 0x10000000, baud rate: 115200
UART sending 3 bytes: AA BB CC 

=== Using SPI Device ===
SPI initialized at 0x10001000, clock freq: 1000000 Hz
SPI sending 3 bytes: AA BB CC 

其对应 的UML图例如下

即:工厂create_device负责创建硬件设备并绑定初始化、发送等方法,客户端只需调用统一接口即可操作不同设备,无需关心 UART 和 SPI 的底层差异,符合嵌入式开发中 "硬件抽象" 的设计思想。

实例 4:工厂方法(数据库连接创建)

为每种数据库(MySQL/SQLite)定义专属工厂,工厂负责创建连接并处理连接配置,客户端直接使用连接执行 SQL。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

// 1. 抽象产品:数据库连接(统一接口)
typedef struct {
    bool (*connect)(struct DBConnection* self, const char* config); // 连接数据库
    bool (*execute)(struct DBConnection* self, const char* sql);   // 执行SQL
    void (*disconnect)(struct DBConnection* self);                 // 断开连接
    void (*destroy)(struct DBConnection* self);
    const char* type;
} DBConnection;

// 2. 抽象工厂:数据库连接工厂(统一创建接口)
typedef struct {
    DBConnection* (*create_connection)(struct DBFactory* self);
    void (*destroy_factory)(struct DBFactory* self);
} DBFactory;

// 3. 具体产品1:MySQL连接
typedef struct {
    DBConnection base;
    char config[128]; // 存储连接配置(如"host:port/db")
} MySQLConnection;

static bool mysql_connect(DBConnection* self, const char* config) {
    MySQLConnection* mysql_conn = (MySQLConnection*)self;
    strncpy(mysql_conn->config, config, sizeof(mysql_conn->config)-1);
    printf("MySQL connecting to: %s\n", config);
    printf("MySQL connected successfully\n");
    return true;
}

static bool mysql_execute(DBConnection* self, const char* sql) {
    (void)self;
    printf("MySQL executing SQL: %s\n", sql);
    return true; // 模拟执行成功
}

static void mysql_disconnect(DBConnection* self) {
    MySQLConnection* mysql_conn = (MySQLConnection*)self;
    printf("MySQL disconnecting from: %s\n", mysql_conn->config);
}

static void mysql_destroy(DBConnection* self) {
    free(self);
}

// 具体工厂1:MySQL连接工厂
typedef struct {
    DBFactory base;
} MySQLFactory;

static DBConnection* mysql_create_conn(DBFactory* self) {
    (void)self;
    MySQLConnection* mysql_conn = malloc(sizeof(MySQLConnection));
    mysql_conn->base.type = "MySQL";
    mysql_conn->base.connect = mysql_connect;
    mysql_conn->base.execute = mysql_execute;
    mysql_conn->base.disconnect = mysql_disconnect;
    mysql_conn->base.destroy = mysql_destroy;
    return (DBConnection*)mysql_conn;
}

static void mysql_destroy_factory(DBFactory* self) {
    free(self);
}

DBFactory* create_mysql_factory() {
    MySQLFactory* factory = malloc(sizeof(MySQLFactory));
    factory->base.create_connection = mysql_create_conn;
    factory->base.destroy_factory = mysql_destroy_factory;
    return (DBFactory*)factory;
}

// 具体产品2:SQLite连接
typedef struct {
    DBConnection base;
    char db_file[64]; // SQLite特有:数据库文件路径
} SQLiteConnection;

static bool sqlite_connect(DBConnection* self, const char* config) {
    SQLiteConnection* sqlite_conn = (SQLiteConnection*)self;
    strncpy(sqlite_conn->db_file, config, sizeof(sqlite_conn->db_file)-1);
    printf("SQLite opening file: %s\n", config);
    printf("SQLite connected successfully\n");
    return true;
}

static bool sqlite_execute(DBConnection* self, const char* sql) {
    (void)self;
    printf("SQLite executing SQL: %s\n", sql);
    return true; // 模拟执行成功
}

static void sqlite_disconnect(DBConnection* self) {
    SQLiteConnection* sqlite_conn = (SQLiteConnection*)self;
    printf("SQLite closing file: %s\n", sqlite_conn->db_file);
}

static void sqlite_destroy(DBConnection* self) {
    free(self);
}

// 具体工厂2:SQLite连接工厂
typedef struct {
    DBFactory base;
} SQLiteFactory;

static DBConnection* sqlite_create_conn(DBFactory* self) {
    (void)self;
    SQLiteConnection* sqlite_conn = malloc(sizeof(SQLiteConnection));
    sqlite_conn->base.type = "SQLite";
    sqlite_conn->base.connect = sqlite_connect;
    sqlite_conn->base.execute = sqlite_execute;
    sqlite_conn->base.disconnect = sqlite_disconnect;
    sqlite_conn->base.destroy = sqlite_destroy;
    return (DBConnection*)sqlite_conn;
}

static void sqlite_destroy_factory(DBFactory* self) {
    free(self);
}

DBFactory* create_sqlite_factory() {
    SQLiteFactory* factory = malloc(sizeof(SQLiteFactory));
    factory->base.create_connection = sqlite_create_conn;
    factory->base.destroy_factory = sqlite_destroy_factory;
    return (DBFactory*)factory;
}

// 客户端使用:通过专属工厂创建数据库连接,统一调用SQL接口
int main() {
    // 1. 使用MySQL工厂创建连接
    DBFactory* mysql_factory = create_mysql_factory();
    DBConnection* mysql_conn = mysql_factory->create_connection(mysql_factory);
    if (mysql_conn) {
        printf("=== Using %s Connection ===\n", mysql_conn->type);
        mysql_conn->connect(mysql_conn, "localhost:3306/mydb");
        mysql_conn->execute(mysql_conn, "SELECT * FROM users");
        mysql_conn->disconnect(mysql_conn);
        mysql_conn->destroy(mysql_conn);
    }
    mysql_factory->destroy_factory(mysql_factory);

    // 2. 使用SQLite工厂创建连接
    DBFactory* sqlite_factory = create_sqlite_factory();
    DBConnection* sqlite_conn = sqlite_factory->create_connection(sqlite_factory);
    if (sqlite_conn) {
        printf("\n=== Using %s Connection ===\n", sqlite_conn->type);
        sqlite_conn->connect(sqlite_conn, "./data.db");
        sqlite_conn->execute(sqlite_conn, "SELECT * FROM logs");
        sqlite_conn->disconnect(sqlite_conn);
        sqlite_conn->destroy(sqlite_conn);
    }
    sqlite_factory->destroy_factory(sqlite_factory);

    return 0;
}

以上代码运行结果为

复制代码
=== Using MySQL Connection ===
MySQL connecting to: localhost:3306/mydb
MySQL connected successfully
MySQL executing SQL: SELECT * FROM users
MySQL disconnecting from: localhost:3306/mydb

=== Using SQLite Connection ===
SQLite opening file: ./data.db
SQLite connected successfully
SQLite executing SQL: SELECT * FROM logs
SQLite closing file: ./data.db

其对应 的UML图例如下

即:工厂方法模式让每种数据库连接有专属工厂,客户端切换数据库时只需替换工厂实例,无需修改连接和 SQL 执行逻辑,适合多数据库兼容的项目(如跨平台应用)。

实例 5:内核风格工厂(内存块创建)

模拟 Linux 内核中通过工厂创建预初始化的内存块,工厂负责内存分配和初始化,客户端直接使用内存块存储数据,符合内核对性能和内存效率的要求。

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

// 1. 抽象产品:内核内存块(统一接口)
#define BLOCK_DATA_SIZE 256 // 内存块数据区大小
typedef struct {
    void (*write)(struct KernelMemBlock* self, const void* data, size_t len); // 写入数据
    void (*read)(struct KernelMemBlock* self, void* buf, size_t len);        // 读取数据
    void (*destroy)(struct KernelMemBlock* self);
    const char* type;
    uint8_t data[BLOCK_DATA_SIZE]; // 数据存储区
    size_t used;                   // 已使用字节数
} KernelMemBlock;

// 2. 定义C语言静态函数(替代C++ Lambda,供所有内存块共用)
// 通用写入实现(普通内存/DMA内存共用)
static void kernel_mem_block_write(KernelMemBlock* self, const void* data, size_t len) {
    if (!self || !data) return; // 空指针保护
    if (self->used + len > BLOCK_DATA_SIZE) {
        printf("MemBlock full: used=%zu, need=%zu\n", self->used, len);
        return;
    }
    memcpy(self->data + self->used, data, len);
    self->used += len;
    printf("%s wrote %zu bytes\n", self->type, len);
}

// 通用读取实现(普通内存/DMA内存共用)
static void kernel_mem_block_read(KernelMemBlock* self, void* buf, size_t len) {
    if (!self || !buf) return; // 空指针保护
    size_t read_len = (len > self->used) ? self->used : len;
    memcpy(buf, self->data, read_len);
    printf("%s read %zu bytes\n", self->type, read_len);
}

// 通用销毁实现
static void kernel_mem_block_destroy(KernelMemBlock* self) {
    free(self);
}

// 3. 简单工厂:内核内存块工厂(创建预初始化的内存块)
typedef enum { MEM_BLOCK_NORMAL, MEM_BLOCK_DMA } MemBlockType; // 普通内存/DMA内存

KernelMemBlock* create_kernel_mem_block(MemBlockType type) {
    KernelMemBlock* block = malloc(sizeof(KernelMemBlock));
    if (!block) return NULL;

    // 初始化通用属性
    memset(block->data, 0, BLOCK_DATA_SIZE);
    block->used = 0;
    // 绑定通用函数(替代Lambda,C语言支持静态函数指针赋值)
    block->write = kernel_mem_block_write;
    block->read = kernel_mem_block_read;
    block->destroy = kernel_mem_block_destroy;

    switch (type) {
        case MEM_BLOCK_NORMAL:
            block->type = "NormalMemBlock";
            // 普通内存块:无额外初始化(通用函数已绑定)
            break;
        case MEM_BLOCK_DMA:
            block->type = "DMAMemBlock";
            // DMA内存块:模拟DMA专用内存初始化(如内存对齐,此处简化)
            printf("DMAMemBlock: Simulated memory alignment (4KB)\n");
            break;
        default:
            free(block);
            printf("Unsupported memory block type\n");
            return NULL;
    }

    printf("Created %s (size: %d bytes)\n", block->type, BLOCK_DATA_SIZE);
    return block;
}

// 客户端使用:模拟内核模块使用内存块
int main() {
    const char* test_data = "Kernel memory block test";
    size_t data_len = strlen(test_data);
    char read_buf[BLOCK_DATA_SIZE];

    // 1. 创建并使用普通内存块
    KernelMemBlock* normal_block = create_kernel_mem_block(MEM_BLOCK_NORMAL);
    if (normal_block) {
        printf("\n=== Using %s ===\n", normal_block->type);
        normal_block->write(normal_block, test_data, data_len);
        memset(read_buf, 0, sizeof(read_buf));
        normal_block->read(normal_block, read_buf, data_len);
        printf("Read data: %s\n", read_buf);
        normal_block->destroy(normal_block);
    }

    // 2. 创建并使用DMA内存块
    KernelMemBlock* dma_block = create_kernel_mem_block(MEM_BLOCK_DMA);
    if (dma_block) {
        printf("\n=== Using %s ===\n", dma_block->type);
        dma_block->write(dma_block, test_data, data_len);
        memset(read_buf, 0, sizeof(read_buf));
        dma_block->read(dma_block, read_buf, data_len);
        printf("Read data: %s\n", read_buf);
        dma_block->destroy(dma_block);
    }

    return 0;
}

以上代码运行结果为

复制代码
Created NormalMemBlock (size: 256 bytes)

=== Using NormalMemBlock ===
NormalMemBlock wrote 24 bytes
NormalMemBlock read 24 bytes
Read data: Kernel memory block test
DMAMemBlock: Simulated memory alignment (4KB)
Created DMAMemBlock (size: 256 bytes)

=== Using DMAMemBlock ===
DMAMemBlock wrote 24 bytes
DMAMemBlock read 24 bytes
Read data: Kernel memory block test

其对应 的UML图例如下

即:模拟 Linux 内核中 "内存块工厂" 的设计,工厂创建内存块时预初始化数据区和读写方法,客户端直接调用统一接口操作内存,无需关心内存是否为 DMA 专用或普通内存,符合内核对 "抽象与封装" 的要求。

四、Linux 内核中的工厂模式应用
  1. 文件系统 inode 工厂(inode_allociget :内核中inode(索引节点)是文件系统的核心对象,inode_alloc函数作为 "简单工厂",负责分配inode结构体并初始化通用属性(如引用计数、类型);不同文件系统(如 ext4、btrfs)通过iget(inode get)函数作为 "工厂方法",从磁盘读取 inode 数据并初始化文件系统特有属性(如 ext4 的i_block_group),最终返回完整的inode对象。
  2. 网络套接字工厂(socket系统调用)socket系统调用是典型的 "简单工厂",通过domain(协议域,如 AF_INET)、type(套接字类型,如 SOCK_STREAM)参数,创建不同类型的套接字对象(如 TCP 套接字、UDP 套接字)。内核通过__sock_create函数统一管理套接字的创建,具体协议(TCP/UDP)的初始化由对应的proto_ops接口完成。
  3. 设备驱动工厂(platform_driver_register :平台设备驱动中,platform_driver_register函数作为 "工厂方法",为每种平台设备(如 GPIO 控制器、UART 控制器)注册专属驱动。当内核检测到匹配的设备时,通过驱动的probe函数(工厂的创建逻辑)初始化设备并创建驱动对象,实现 "设备与驱动的动态匹配"。
  4. 内存分配工厂(kmallocvmallockmallocvmalloc是内核中的 "内存块工厂":kmalloc创建物理连续的内存块,vmalloc创建虚拟连续但物理不连续的内存块。两者作为 "工厂方法",隐藏内存分配的底层细节(如伙伴系统、页表映射),客户端只需传入内存大小即可获取内存块,无需关心内存的物理分布。
  5. 信号量工厂(sema_initdown/up :内核信号量(struct semaphore)的创建通过sem_init函数完成,该函数作为 "简单工厂",初始化信号量的计数和等待队列。客户端通过down(获取信号量)和up(释放信号量)接口使用信号量,无需关心等待队列的管理和调度细节,工厂已封装所有创建和初始化逻辑。
五、实现注意事项
  1. 对象接口的一致性 :抽象产品(如ShapeLogger)的函数指针接口需统一,确保不同具体产品的方法参数和返回值一致,客户端才能通过抽象接口透明使用不同对象。
  2. 资源释放的完整性 :工厂创建的对象必须提供明确的destroy方法,确保内存分配的对象能被正确释放;工厂本身(尤其是工厂方法模式中的工厂)也需提供destroy_factory方法,避免工厂实例的内存泄漏。
  3. 简单工厂与工厂方法的选择
    • 简单工厂:适合对象类型少(如≤5 种)、变化不频繁的场景,代码简洁但扩展时需修改工厂;
    • 工厂方法:适合对象类型多、频繁扩展的场景,扩展时无需修改旧代码但工厂数量较多,需权衡代码复杂度。
  4. 线程安全的保障 :多线程环境下,若工厂共享全局状态(如对象计数器、资源池),需通过互斥锁(如pthread_mutex_t)保护,避免并发创建对象导致的状态不一致或内存错误。
  5. 参数传递的安全性 :简单工厂通过参数区分对象类型时,需校验参数合法性(如switchdefault分支);工厂方法模式中,工厂的配置参数(如文件日志的文件名)需确保非空且合法,避免空指针或非法配置导致的崩溃。
六、补充说明
  • 工厂模式与抽象工厂模式的区别:工厂模式专注于创建单一类型的对象 (如日志器、形状),抽象工厂模式专注于创建多个相关的对象家族(如 "日志格式化器 + 日志输出器");前者是 "单一对象创建",后者是 "家族对象创建"。
  • 工厂模式的扩展:
    • 对象池化 :工厂可预分配一批对象存入 "对象池",客户端请求时直接从池获取,避免频繁malloc/free的开销(如内核的 slab 分配器);
    • 懒加载创建:工厂在客户端首次请求对象时才创建,而非启动时创建所有对象,减少初始化资源消耗(如内核模块的驱动工厂)。
  • 适用场景:对象创建复杂、需批量创建同类型对象、对象类型需扩展、需隐藏创建细节(如内核、嵌入式开发)等场景。

通过工厂模式,C 语言程序(尤其是 Linux 内核)能够集中管理对象创建,降低耦合、提升扩展性,是构建模块化、可维护系统的核心技术之一。内核中大量核心组件(如 inode、套接字、内存块)均采用工厂模式设计,体现了 "创建与使用分离" 的设计思想。

|---------------------|
| 点击下面关注,获取最新最全分享,不迷路 |

相关推荐
qq_479875433 小时前
X-Macros(1)
linux·服务器·windows
笨笨聊运维4 小时前
CentOS官方不维护版本,配置python升级方法,无损版
linux·python·centos
Want5954 小时前
C/C++跳动的爱心①
c语言·开发语言·c++
lingggggaaaa4 小时前
免杀对抗——C2远控篇&C&C++&DLL注入&过内存核晶&镂空新增&白加黑链&签名程序劫持
c语言·c++·学习·安全·网络安全·免杀对抗
phdsky4 小时前
【设计模式】建造者模式
c++·设计模式·建造者模式
小毛驴8504 小时前
软件设计模式-装饰器模式
python·设计模式·装饰器模式
gfdhy4 小时前
【c++】哈希算法深度解析:实现、核心作用与工业级应用
c语言·开发语言·c++·算法·密码学·哈希算法·哈希
HIT_Weston5 小时前
39、【Ubuntu】【远程开发】拉出内网 Web 服务:构建静态网页(二)
linux·前端·ubuntu
我不会插花弄玉5 小时前
vs2022调试基础篇【由浅入深-C语言】
c语言