用C语言实现代理模式

代理模式(Proxy Pattern)的核心是为对象提供一个代理,通过代理控制对原对象的访问 ,常用于添加额外逻辑(如权限校验、缓存、远程访问等)而不修改原对象。在C语言中,可以通过结构体封装原对象指针+重写接口方法实现:代理对象实现与原对象相同的接口,内部调用原对象方法并添加控制逻辑。

C语言实现代理模式的思路

  1. 抽象主题(Subject):定义原对象和代理对象的统一接口(函数指针结构体)。
  2. 真实主题(Real Subject):实现抽象主题的核心功能(被代理的对象)。
  3. 代理(Proxy):实现抽象主题接口,内部包含真实主题的指针,在调用真实主题方法前/后添加控制逻辑(如权限检查、日志记录)。

示例:文件操作代理(添加权限校验)

假设需要一个文件读写模块,要求只有管理员权限才能写入文件,普通用户只能读取。通过代理模式在不修改原始文件操作逻辑的前提下添加权限控制。

步骤1:定义抽象主题(文件操作接口)
c 复制代码
// 抽象主题:文件操作接口
typedef struct FileSubject {
    // 读取文件内容
    char* (*read)(struct FileSubject* self, const char* filename);
    // 写入文件内容
    int (*write)(struct FileSubject* self, const char* filename, const char* content);
    // 销毁对象
    void (*destroy)(struct FileSubject* self);
} FileSubject;
步骤2:实现真实主题(原始文件操作)
c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 真实主题:原始文件操作(无权限控制)
typedef struct {
    FileSubject subject; // 继承抽象接口
} RealFileOperator;

// 原始读取逻辑:读取文件内容(简单实现)
static char* real_read(FileSubject* self, const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) return NULL;

    // 获取文件大小
    fseek(file, 0, SEEK_END);
    long size = ftell(file);
    fseek(file, 0, SEEK_SET);

    // 分配内存并读取内容
    char* content = (char*)malloc(size + 1);
    if (content) {
        fread(content, 1, size, file);
        content[size] = '\0';
    }

    fclose(file);
    return content;
}

// 原始写入逻辑:写入文件内容
static int real_write(FileSubject* self, const char* filename, const char* content) {
    FILE* file = fopen(filename, "w");
    if (!file) return 0;

    fputs(content, file);
    fclose(file);
    return 1; // 写入成功
}

// 真实主题的销毁
static void real_destroy(FileSubject* self) {
    free(self); // 释放真实对象内存
}

// 创建真实文件操作对象
FileSubject* real_file_operator_create() {
    RealFileOperator* real = (RealFileOperator*)malloc(sizeof(RealFileOperator));
    if (!real) return NULL;

    // 绑定接口方法
    real->subject.read = real_read;
    real->subject.write = real_write;
    real->subject.destroy = real_destroy;

    return (FileSubject*)real;
}
步骤3:实现代理(添加权限控制)

代理对象包含真实主题的指针,并在read/write方法中添加权限校验逻辑。

c 复制代码
// 权限类型(用于代理控制)
typedef enum {
    USER_GUEST,    // 访客(只读)
    USER_ADMIN     // 管理员(读写)
} UserType;

// 代理:带权限控制的文件操作
typedef struct {
    FileSubject subject;       // 继承抽象接口
    FileSubject* real_subject; // 指向真实主题(被代理对象)
    UserType user_type;        // 代理的额外属性:用户权限
} FileProxy;

// 代理的读取逻辑:允许所有用户读取
static char* proxy_read(FileSubject* self, const char* filename) {
    FileProxy* proxy = (FileProxy*)self;
    printf("[代理] 用户<%d>尝试读取文件: %s\n", proxy->user_type, filename);
    
    // 调用真实主题的读取方法
    char* content = proxy->real_subject->read(proxy->real_subject, filename);
    
    if (content) {
        printf("[代理] 读取成功\n");
    } else {
        printf("[代理] 读取失败\n");
    }
    return content;
}

// 代理的写入逻辑:仅管理员可写入
static int proxy_write(FileSubject* self, const char* filename, const char* content) {
    FileProxy* proxy = (FileProxy*)self;
    printf("[代理] 用户<%d>尝试写入文件: %s\n", proxy->user_type, filename);
    
    // 权限校验(代理的核心控制逻辑)
    if (proxy->user_type != USER_ADMIN) {
        printf("[代理] 权限不足:仅管理员可写入\n");
        return 0; // 写入失败
    }
    
    // 权限通过,调用真实主题的写入方法
    int result = proxy->real_subject->write(proxy->real_subject, filename, content);
    printf("[代理] 写入%s\n", result ? "成功" : "失败");
    return result;
}

// 代理的销毁:先销毁真实主题,再释放自身
static void proxy_destroy(FileSubject* self) {
    FileProxy* proxy = (FileProxy*)self;
    proxy->real_subject->destroy(proxy->real_subject); // 销毁被代理对象
    free(proxy); // 释放代理对象
}

// 创建文件代理(绑定真实主题和用户权限)
FileSubject* file_proxy_create(FileSubject* real_subject, UserType user_type) {
    if (!real_subject) return NULL;
    FileProxy* proxy = (FileProxy*)malloc(sizeof(FileProxy));
    if (!proxy) return NULL;

    // 绑定接口方法(重写read和write,添加控制逻辑)
    proxy->subject.read = proxy_read;
    proxy->subject.write = proxy_write;
    proxy->subject.destroy = proxy_destroy;
    // 关联真实主题和用户权限
    proxy->real_subject = real_subject;
    proxy->user_type = user_type;

    return (FileSubject*)proxy;
}
步骤4:使用代理模式

客户端通过代理对象访问文件,无需直接操作真实主题,权限控制逻辑由代理透明处理。

c 复制代码
int main() {
    // 1. 创建真实文件操作对象(被代理)
    FileSubject* real_file_op = real_file_operator_create();
    if (!real_file_op) {
        printf("创建真实文件操作失败\n");
        return 1;
    }

    // 2. 创建访客代理(权限:只读)
    FileSubject* guest_proxy = file_proxy_create(real_file_op, USER_GUEST);
    if (!guest_proxy) {
        real_file_op->destroy(real_file_op);
        return 1;
    }

    // 访客尝试写入(预期失败)
    guest_proxy->write(guest_proxy, "test.txt", "访客写入的内容");
    // 访客尝试读取(预期成功)
    char* content = guest_proxy->read(guest_proxy, "test.txt");
    if (content) {
        printf("读取到内容: %s\n", content);
        free(content); // 释放读取的内容
    }

    // 3. 销毁访客代理(会自动销毁真实对象,需重新创建)
    guest_proxy->destroy(guest_proxy);

    // 重新创建真实对象和管理员代理
    real_file_op = real_file_operator_create();
    FileSubject* admin_proxy = file_proxy_create(real_file_op, USER_ADMIN);
    
    // 管理员尝试写入(预期成功)
    admin_proxy->write(admin_proxy, "test.txt", "管理员写入的内容");
    // 管理员尝试读取(预期成功)
    content = admin_proxy->read(admin_proxy, "test.txt");
    if (content) {
        printf("读取到内容: %s\n", content);
        free(content);
    }

    // 销毁管理员代理
    admin_proxy->destroy(admin_proxy);
    return 0;
}

输出结果

复制代码
[代理] 用户<0>尝试写入文件: test.txt
[代理] 权限不足:仅管理员可写入
[代理] 用户<0>尝试读取文件: test.txt
[代理] 读取失败
[代理] 用户<1>尝试写入文件: test.txt
[代理] 写入成功
[代理] 用户<1>尝试读取文件: test.txt
[代理] 读取成功
读取到内容: 管理员写入的内容

核心思想总结

  1. 控制访问:代理通过在调用真实对象方法前添加逻辑(如权限校验),实现对原对象的访问控制,且不修改原对象代码。
  2. 透明性 :代理与真实对象实现相同的FileSubject接口,客户端无需区分,可无缝切换。
  3. 功能扩展:除权限控制外,代理还可添加缓存(重复读取时返回缓存内容)、日志记录、远程访问(代理作为本地对象,实际调用远程服务)等功能。

C语言通过结构体封装真实对象指针和额外属性(如user_type),结合函数指针重写实现了代理模式的核心,适合需要在不侵入原逻辑的前提下增强对象功能的场景。

相关推荐
Yupureki5 小时前
从零开始的C++学习生活 13:红黑树全面解析
c语言·数据结构·c++·学习·visual studio
AAA小肥杨7 小时前
cmake使用教程
c语言·c++·cmake
.小小陈.8 小时前
数据结构3:复杂度
c语言·开发语言·数据结构·笔记·学习·算法·visual studio
云知谷9 小时前
【经典书籍】C++ Primer 第16章模板与泛型编程精华讲解
c语言·开发语言·c++·软件工程·团队开发
屁股割了还要学9 小时前
【Linux入门】常用工具:yum、vim
linux·运维·服务器·c语言·c++·学习·考研
Jm_洋洋10 小时前
【Linux系统编程】程序替换:execve(execl、execlp、execle、execv、execvp、execvpe)
linux·运维·c语言·开发语言·程序人生
小莞尔10 小时前
【51单片机】【protues仿真】基于51单片机秒表计时器系统(带存储)
c语言·stm32·单片机·嵌入式硬件·物联网·51单片机
闭着眼睛学算法10 小时前
【双机位A卷】华为OD笔试之【哈希表】双机位A-跳房子I【Py/Java/C++/C/JS/Go六种语言】【欧弟算法】全网注释最详细分类最全的华子OD真题题解
java·c语言·c++·python·算法·华为od·散列表
代码改善世界11 小时前
C语言内存机制深度解析:指针运算、数组与字符串实战指南
c语言