结构型模式:⑦代理模式(Proxy Pattern)

结构型模式:⑦代理模式(Proxy Pattern)

核心思想

为目标对象提供一个 “代理”(中间层),由代理控制对目标对象的访问,并在访问前后添加额外逻辑(如日志记录、权限校验、缓存、远程调用转发等)。核心是 “代理与目标对象实现同一接口”,客户端无需区分代理和目标对象,通过代理即可间接操作目标对象,实现功能增强或访问控制。

核心本质

控制访问 + 功能增强,代理不改变目标对象的核心逻辑,仅在 “转发请求” 的前后插入额外行为,同时隔离客户端与目标对象,降低耦合。

典型场景

远程代理:代理本地对象,转发请求到远程服务器(如 RPC 代理);
安全代理:访问目标对象前校验权限(如管理员权限校验);
日志代理:记录目标对象的访问日志(如接口调用时间、参数);
缓存代理:缓存目标对象的结果,重复请求直接返回缓存(如数据库查询缓存)。

C语言编写

场景示例

图片加载:
目标对象(RealImage):负责实际加载图片(核心逻辑);
代理对象(ProxyImage):持有 RealImage 指针,加载图片前记录日志、校验权限,加载后记录完成日志;
客户端通过代理访问图片加载功能,无需直接操作 RealImage。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 最大图片路径长度
#define MAX_PATH 128

// -------------------------- 1. 抽象接口(Subject):图片加载统一接口 --------------------------
typedef struct Image {
    // 统一接口:显示图片(核心功能)
    void (*display)(struct Image* self);
    // 销毁接口
    void (*destroy)(struct Image* self);
    char path[MAX_PATH]; // 图片路径(目标对象和代理共享的参数)
} Image;

// -------------------------- 2. 目标对象(RealSubject):真实图片加载器 --------------------------
typedef struct RealImage {
    Image base; // 模拟继承:实现统一接口
} RealImage;

// 目标对象:实际加载图片(核心逻辑)
void real_image_display(Image* self) {
    printf("【真实图片】加载图片:%s(耗时200ms)\n", self->path);
}

// 目标对象:销毁
void real_image_destroy(Image* self) {
    if (self != NULL) {
        free(self);
        printf("【真实图片】销毁资源\n");
    }
}

// 创建目标对象(真实图片加载器)
Image* create_real_image(const char* path) {
    RealImage* real = (RealImage*)malloc(sizeof(RealImage));
    strncpy(real->base.path, path, MAX_PATH);
    real->base.display = real_image_display;
    real->base.destroy = real_image_destroy;
    return (Image*)real;
}

// -------------------------- 3. 代理对象(Proxy):图片加载代理 --------------------------
typedef struct ProxyImage {
    Image base;          // 模拟继承:实现统一接口
    Image* real_image;   // 组合核心:持有目标对象指针
    int is_authorized;   // 代理额外状态:权限标识(控制访问)
} ProxyImage;

// 代理:权限校验(额外逻辑)
int proxy_check_auth(ProxyImage* proxy) {
    // 模拟权限校验:仅管理员有权限加载
    proxy->is_authorized = 1; // 简化示例:默认授权
    printf("【代理】校验访问权限:%s\n", proxy->is_authorized ? "通过" : "拒绝");
    return proxy->is_authorized;
}

// 代理:记录日志(额外逻辑)
void proxy_log(ProxyImage* proxy, const char* action) {
    printf("【代理】日志记录:%s图片[%s]\n", action, proxy->base.path);
}

// 代理:转发请求(核心逻辑)
void proxy_image_display(Image* self) {
    ProxyImage* proxy = (ProxyImage*)self;
    
    // 1. 代理前置逻辑:日志+权限校验
    proxy_log(proxy, "开始加载");
    if (!proxy_check_auth(proxy)) {
        printf("【代理】权限不足,无法加载图片!\n");
        return;
    }

    // 2. 延迟初始化目标对象(优化:仅在需要时创建真实对象)
    if (proxy->real_image == NULL) {
        proxy->real_image = create_real_image(self->path);
        printf("【代理】初始化真实图片加载器\n");
    }

    // 3. 转发请求到目标对象
    proxy->real_image->display(proxy->real_image);

    // 4. 代理后置逻辑:记录完成日志
    proxy_log(proxy, "加载完成");
}

// 代理:销毁(需同时销毁目标对象)
void proxy_image_destroy(Image* self) {
    if (self != NULL) {
        ProxyImage* proxy = (ProxyImage*)self;
        // 销毁目标对象
        if (proxy->real_image != NULL) {
            proxy->real_image->destroy(proxy->real_image);
        }
        free(proxy);
        printf("【代理】销毁代理资源\n");
    }
}

// 创建代理对象
Image* create_proxy_image(const char* path) {
    ProxyImage* proxy = (ProxyImage*)malloc(sizeof(ProxyImage));
    strncpy(proxy->base.path, path, MAX_PATH);
    proxy->base.display = proxy_image_display;
    proxy->base.destroy = proxy_image_destroy;
    proxy->real_image = NULL; // 初始不创建目标对象(延迟初始化)
    proxy->is_authorized = 0;
    return (Image*)proxy;
}

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 客户端通过代理访问图片加载功能(无需直接操作RealImage)
    Image* proxy = create_proxy_image("风景.jpg");
    printf("=== 第一次加载图片 ===\n");
    proxy->display(proxy); // 调用代理的display,代理转发到RealImage

    printf("\n=== 第二次加载图片 ===\n");
    proxy->display(proxy); // 目标对象已初始化,直接复用,仅执行代理逻辑

    // 2. 销毁代理(间接销毁目标对象)
    printf("\n=== 销毁资源 ===\n");
    proxy->destroy(proxy);

    return 0;
}

关键要点

1.接口统一:目标对象(RealImage)和代理对象(ProxyImage)都实现 Image 接口(display/destroy 函数指针),客户端无需区分,直接调用接口即可。
2.组合持有目标对象:代理通过 real_image 指针持有目标对象,而非继承,降低耦合,目标对象可独立变化。
3.额外逻辑增强:代理在转发请求前后添加额外功能(日志、权限校验),不修改目标对象的核心逻辑,符合 “开闭原则”。
4.延迟初始化优化:代理可延迟创建目标对象(第一次加载时才初始化),节省内存(若客户端仅创建代理而不调用,无需创建真实对象)。
5.访问控制:代理可通过权限校验等逻辑控制对目标对象的访问(如拒绝无权限请求),实现 “安全代理”。
6.内存管理:代理的 destroy 方法需递归销毁目标对象,避免仅销毁代理导致的目标对象内存泄漏。

C++语言实现(类 + 继承 + 多态 + 组合)

场景示例

同 C 语言:图片加载(抽象基类 Image、目标类 RealImage、代理类 ProxyImage),代理添加日志、权限校验、延迟初始化功能。 通过 “抽象基类 + 纯虚函数” 定义统一接口,代理类继承抽象基类并持有目标类的智能指针(组合关系),利用多态实现透明转发,代码更简洁、类型更安全。

#include <iostream>
#include <string>
#include <memory> // 智能指针(自动管理内存)

// -------------------------- 1. 抽象接口(Subject):图片加载基类 --------------------------
class Image {
public:
    virtual ~Image() = default; // 虚析构:确保子类析构被调用
    // 纯虚函数:统一接口(强制子类实现)
    virtual void Display() const = 0;
    virtual std::string GetPath() const = 0;
};

// -------------------------- 2. 目标对象(RealSubject):真实图片加载器 --------------------------
class RealImage : public Image {
public:
    explicit RealImage(std::string path) : path_(std::move(path)) {}

    std::string GetPath() const override {
        return path_;
    }

    // 目标对象核心逻辑:实际加载图片
    void Display() const override {
        std::cout << "【真实图片】加载图片:" << path_ << "(耗时200ms)" << std::endl;
    }

private:
    std::string path_; // 图片路径
};

// -------------------------- 3. 代理对象(Proxy):图片加载代理 --------------------------
class ProxyImage : public Image {
public:
    explicit ProxyImage(std::string path) : path_(std::move(path)), is_authorized_(false) {}

    std::string GetPath() const override {
        return path_;
    }

    // 代理:权限校验(额外逻辑)
    bool CheckAuth() const {
        // 模拟权限校验:默认授权
        is_authorized_ = true;
        std::cout << "【代理】校验访问权限:" << (is_authorized_ ? "通过" : "拒绝") << std::endl;
        return is_authorized_;
    }

    // 代理:记录日志(额外逻辑)
    void Log(const std::string& action) const {
        std::cout << "【代理】日志记录:" << action << "图片[" << path_ << "]" << std::endl;
    }

    // 代理:转发请求(核心逻辑)
    void Display() const override {
        // 1. 代理前置逻辑:日志+权限校验
        Log("开始加载");
        if (!CheckAuth()) {
            std::cout << "【代理】权限不足,无法加载图片!" << std::endl;
            return;
        }

        // 2. 延迟初始化目标对象(智能指针自动管理内存)
        if (!real_image_) {
            real_image_ = std::make_shared<RealImage>(path_);
            std::cout << "【代理】初始化真实图片加载器" << std::endl;
        }

        // 3. 转发请求到目标对象(多态调用)
        real_image_->Display();

        // 4. 代理后置逻辑:记录完成日志
        Log("加载完成");
    }

private:
    std::string path_; // 图片路径
    mutable bool is_authorized_; // 权限标识(mutable:const方法中可修改)
    mutable std::shared_ptr<RealImage> real_image_; // 持有目标对象(智能指针自动销毁)
};

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 客户端通过代理访问图片加载功能(仅依赖抽象接口Image)
    std::shared_ptr<Image> proxy = std::make_shared<ProxyImage>("风景.jpg");
    std::cout << "=== 第一次加载图片 ===" << std::endl;
    proxy->Display(); // 多态调用代理的Display

    std::cout << "\n=== 第二次加载图片 ===" << std::endl;
    proxy->Display(); // 复用已初始化的目标对象

    return 0; // 智能指针自动销毁代理和目标对象,无需手动释放
}

关键要点

1.接口统一:抽象基类 Image 定义纯虚函数 Display/GetPath,目标类和代理类都继承该基类,客户端仅依赖抽象接口,实现 “依赖倒置”。
2.多态转发:客户端通过 Image 智能指针调用 Display,实际执行代理类的实现,代理内部转发到目标类,客户端无感知代理的存在。
3.组合 + 智能指针:代理类通过 std::shared_ptr 持有目标对象,智能指针自动管理内存,避免内存泄漏;虚析构函数确保子类析构被正确调用。
4.额外逻辑增强:代理在 Display 中添加日志、权限校验等额外功能,目标类仅关注核心加载逻辑,职责分离。
5.延迟初始化:代理延迟创建目标对象(第一次调用 Display 时初始化),优化内存使用(若代理未被调用,无需创建真实对象)。
6.类型安全:C++ 的编译期类型检查和多态机制,避免 C 语言中函数指针绑定错误或类型转换风险,代码更可靠。

代理模式核心总结(C vs C++)

在这里插入图片描述

设计原则

开闭原则:增强目标对象功能时,无需修改目标类,仅需新增代理类;
依赖倒置原则:客户端依赖抽象接口,不依赖具体目标类或代理类;
单一职责原则:目标类负责核心逻辑,代理类负责访问控制和功能增强,职责清晰。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值