Open Close Principle(OCP)

一.what is open-close-principle

OCP 是指软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。


二.OCP的设计准则

  • 对扩展开放:当需求变化时,我们应该能够通过添加新的代码来满足需求,而不是修改现有的代码。比如添加新的功能、支持新的类型等。
  • 对修改关闭:一旦软件实体(模块、函数等)被实现,就不应该对其进行修改。这是为了确保软件的稳定性和可靠性。
  • 使用抽象:通过抽象(如接口、抽象类等)来定义软件实体的行为,使得具体实现可以独立于抽象而变化。

三.举例

3.1 设备驱动反例

每次新增一种设备类型(例如SPI、USB),都要修改这个 switch,违反开闭原则。

点击查看代码
typedef enum {
    DEV_UART,
    DEV_GPIO,
    DEV_I2C
} DevType;

int dev_open(DevType type, const char *name) {
    switch (type) {
        case DEV_UART:
            // UART open logic
            break;
        case DEV_GPIO:
            // GPIO open logic
            break;
        case DEV_I2C:
            // I2C open logic
            break;
        default:
            return -1;
    }
    // 同理 read/write/close 都要有switch
    // 新增SPI或USB,就要改所有函数的switch
}

3.2 设备驱动正确实现

用结构体 + 函数指针表(vtable)模拟虚函数表,实现设备抽象。每个设备类型有一个“驱动”结构体,核心操作通过指针调用。


dev_abstraction.h

点击查看代码
// dev_abstraction.h
#ifndef DEV_ABSTRACTION_H
#define DEV_ABSTRACTION_H

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

// 设备句柄(opaque,用户不关心内部)
typedef struct dev_handle dev_handle_t;

// 设备操作vtable(函数指针表)
typedef struct {
    int  (*open)(dev_handle_t *h, const char *name, int flags);
    int  (*read)(dev_handle_t *h, void *buf, size_t len);
    int  (*write)(dev_handle_t *h, const void *buf, size_t len);
    void (*close)(dev_handle_t *h);
    int  (*ioctl)(dev_handle_t *h, int cmd, void *arg);  // 可选控制
} dev_ops_t;

// 设备类型注册项
typedef struct dev_driver {
    const char   *type_name;      // "uart", "gpio", "i2c", "spi"...
    dev_ops_t     ops;
    size_t        priv_size;      // 私有数据大小(每个驱动自定义)
} dev_driver_t;

// 设备句柄结构(内部)
struct dev_handle {
    const dev_driver_t *driver;
    void               *priv;     // 驱动私有数据
    // ... 可加引用计数等
};

// 核心API(永远不改)
void dev_register_driver(const dev_driver_t *driver);

// 创建设备句柄(按类型名查找驱动)
dev_handle_t *dev_create(const char *type_name);

// 通用操作(通过vtable调用)
int  dev_open(dev_handle_t *h, const char *name, int flags);
int  dev_read(dev_handle_t *h, void *buf, size_t len);
int  dev_write(dev_handle_t *h, const void *buf, size_t len);
void dev_close(dev_handle_t *h);
int  dev_ioctl(dev_handle_t *h, int cmd, void *arg);

#endif

dev_abstraction.c

点击查看代码
// dev_abstraction.c
#include "dev_abstraction.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_DRIVERS 32

static const dev_driver_t *drivers[MAX_DRIVERS] = {0};
static int driver_count = 0;

void dev_register_driver(const dev_driver_t *driver)
{
    if (driver_count >= MAX_DRIVERS) {
        fprintf(stderr, "too many device drivers\n");
        return;
    }
    drivers[driver_count++] = driver;
}

static const dev_driver_t *find_driver(const char *type_name)
{
    for (int i = 0; i < driver_count; i++) {
        const dev_driver_t *d = drivers[i];
        if (d && strcmp(d->type_name, type_name) == 0)
            return d;
    }
    return NULL;
}

dev_handle_t *dev_create(const char *type_name)
{
    const dev_driver_t *d = find_driver(type_name);
    if (!d) {
        fprintf(stderr, "unknown device type: %s\n", type_name);
        return NULL;
    }

    dev_handle_t *h = malloc(sizeof(dev_handle_t));
    if (!h) return NULL;

    h->driver = d;
    h->priv = (d->priv_size > 0) ? calloc(1, d->priv_size) : NULL;

    return h;
}

// 通用操作(委托给vtable,永远不改)
int dev_open(dev_handle_t *h, const char *name, int flags)
{
    if (!h || !h->driver || !h->driver->ops.open) return -1;
    return h->driver->ops.open(h, name, flags);
}

int dev_read(dev_handle_t *h, void *buf, size_t len)
{
    if (!h || !h->driver || !h->driver->ops.read) return -1;
    return h->driver->ops.read(h, buf, len);
}

int dev_write(dev_handle_t *h, const void *buf, size_t len)
{
    if (!h || !h->driver || !h->driver->ops.write) return -1;
    return h->driver->ops.write(h, buf, len);
}

void dev_close(dev_handle_t *h)
{
    if (!h || !h->driver || !h->driver->ops.close) return;
    h->driver->ops.close(h);
    free(h->priv);
    free(h);
}

int dev_ioctl(dev_handle_t *h, int cmd, void *arg)
{
    if (!h || !h->driver || !h->driver->ops.ioctl) return -1;
    return h->driver->ops.ioctl(h, cmd, arg);
}


新增UART驱动,不需要修改核心代码。

uart_driver.c

点击查看代码
// uart_driver.c
#include "dev_abstraction.h"
#include <stdio.h>  // 模拟实际硬件操作

typedef struct {
    FILE *fp;  // 模拟串口文件
} uart_priv_t;

static int uart_open(dev_handle_t *h, const char *name, int flags)
{
    uart_priv_t *p = h->priv;
    p->fp = fopen(name, "r+");  // 模拟 /dev/ttyS0
    return p->fp ? 0 : -1;
}

static int uart_read(dev_handle_t *h, void *buf, size_t len)
{
    uart_priv_t *p = h->priv;
    return fread(buf, 1, len, p->fp);
}

static int uart_write(dev_handle_t *h, const void *buf, size_t len)
{
    uart_priv_t *p = h->priv;
    return fwrite(buf, 1, len, p->fp);
}

static void uart_close(dev_handle_t *h)
{
    uart_priv_t *p = h->priv;
    if (p->fp) fclose(p->fp);
}

static int uart_ioctl(dev_handle_t *h, int cmd, void *arg)
{
    // 模拟设置波特率等
    return 0;
}

static const dev_driver_t uart_driver = {
    .type_name = "uart",
    .ops = {
        .open  = uart_open,
        .read  = uart_read,
        .write = uart_write,
        .close = uart_close,
        .ioctl = uart_ioctl
    },
    .priv_size = sizeof(uart_priv_t)
};

__attribute__((constructor))
static void register_uart(void)
{
    dev_register_driver(&uart_driver);
}



main.c
点击查看代码
int main(void)
{
    dev_handle_t *h = dev_create("uart");
    if (!h) return 1;

    if (dev_open(h, "/dev/ttyS0", 0) != 0) {
        dev_close(h);
        return 1;
    }

    char buf[128] = "Hello, device!";
    dev_write(h, buf, strlen(buf));

    memset(buf, 0, sizeof(buf));
    dev_read(h, buf, sizeof(buf));
    printf("Read: %s\n", buf);

    dev_ioctl(h, 0x1234, NULL);  // 自定义命令

    dev_close(h);

    // 新增"spi"驱动后,直接dev_create("spi")即可,无需改main
    return 0;
}
posted @ 2026-02-22 19:36  自由的Charles  阅读(25)  评论(0)    收藏  举报