结构型模式:⑦代理模式(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++)

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

被折叠的 条评论
为什么被折叠?



