C++设计模式之代理模式详解
·
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理(Placeholder)以控制对这个对象的访问。代理模式通过引入一个代理对象,在不改变原始对象接口的前提下,为其增加额外的功能,如访问控制、延迟加载、日志记录等。
代理模式的核心角色
- 抽象主题(Subject):定义代理和真实主题的共同接口
- 真实主题(Real Subject):实际执行业务逻辑的对象
- 代理(Proxy):实现抽象主题接口,包含对真实主题的引用,控制对真实主题的访问
代理模式的常见类型及实现
1. 虚拟代理(Virtual Proxy)
延迟创建开销较大的对象,直到真正需要时才初始化。
#include <iostream>
#include <string>
// 抽象主题:图片
class Image {
public:
virtual void display() = 0;
virtual ~Image() = default;
};
// 真实主题:高分辨率图片
class HighResolutionImage : public Image {
private:
std::string filename;
// 模拟加载图片的耗时操作
void loadFromDisk() {
std::cout << "从磁盘加载高分辨率图片: " << filename << std::endl;
}
public:
HighResolutionImage(const std::string& name) : filename(name) {
// 实际项目中,这里可能包含耗时的加载操作
}
void display() override {
loadFromDisk();
std::cout << "显示高分辨率图片: " << filename << std::endl;
}
};
// 虚拟代理:延迟加载图片
class ImageProxy : public Image {
private:
HighResolutionImage* realImage;
std::string filename;
// 懒加载:只在需要时创建真实对象
void ensureImageLoaded() {
if (!realImage) {
realImage = new HighResolutionImage(filename);
}
}
public:
ImageProxy(const std::string& name) : filename(name), realImage(nullptr) {}
~ImageProxy() override {
delete realImage;
}
void display() override {
ensureImageLoaded();
realImage->display();
}
};
// 客户端使用
int main() {
std::cout << "创建图片代理..." << std::endl;
Image* image = new ImageProxy("风景照.jpg"); // 此时并未加载真实图片
std::cout << "\n第一次显示图片:" << std::endl;
image->display(); // 第一次显示时才真正加载
std::cout << "\n第二次显示图片:" << std::endl;
image->display(); // 直接使用已加载的图片
delete image;
return 0;
}
2. 保护代理(Protection Proxy)
控制对敏感对象的访问,根据权限决定是否允许操作。
#include <iostream>
#include <string>
// 用户类:存储用户信息和权限
class User {
private:
std::string name;
bool isAdmin;
public:
User(const std::string& userName, bool admin)
: name(userName), isAdmin(admin) {}
bool isAdministrator() const {
return isAdmin;
}
std::string getName() const {
return name;
}
};
// 抽象主题:文件
class File {
public:
virtual void read() = 0;
virtual void write(const std::string& content) = 0;
virtual ~File() = default;
};
// 真实主题:实际文件
class RealFile : public File {
private:
std::string filename;
public:
RealFile(const std::string& name) : filename(name) {}
void read() override {
std::cout << "读取文件内容: " << filename << std::endl;
}
void write(const std::string& content) override {
std::cout << "向文件 " << filename << " 写入内容: " << content << std::endl;
}
};
// 保护代理:控制文件访问权限
class FileProxy : public File {
private:
RealFile* realFile;
User* user;
public:
FileProxy(const std::string& filename, User* user)
: realFile(new RealFile(filename)), user(user) {}
~FileProxy() override {
delete realFile;
}
void read() override {
// 任何人都可以读取
std::cout << "用户 " << user->getName() << " 尝试读取文件..." << std::endl;
realFile->read();
}
void write(const std::string& content) override {
// 只有管理员可以写入
if (user->isAdministrator()) {
std::cout << "管理员 " << user->getName() << " 尝试写入文件..." << std::endl;
realFile->write(content);
} else {
std::cout << "权限不足! 用户 " << user->getName() << " 没有写入权限。" << std::endl;
}
}
};
// 客户端使用
int main() {
// 创建普通用户和管理员
User* normalUser = new User("张三", false);
User* adminUser = new User("李四", true);
// 使用代理访问文件
File* file = new FileProxy("重要文档.txt", normalUser);
std::cout << "=== 普通用户操作 ===" << std::endl;
file->read();
file->write("添加一些内容");
// 更换用户
delete file;
file = new FileProxy("重要文档.txt", adminUser);
std::cout << "\n=== 管理员操作 ===" << std::endl;
file->read();
file->write("添加一些内容");
// 清理资源
delete file;
delete normalUser;
delete adminUser;
return 0;
}
代理模式的其他常见类型
- 远程代理(Remote Proxy):为远程对象提供本地代表,常用于分布式系统
- 智能引用(Smart Reference):在访问对象时执行额外操作,如计数引用、自动释放等
- 缓存代理(Cache Proxy):为 expensive 操作的结果提供缓存,如数据库查询缓存
代理模式与装饰器模式的区别
- 代理模式:主要控制对对象的访问,侧重于"控制"
- 装饰器模式:主要为对象添加功能,侧重于"增强"
代理模式的应用场景
- 延迟加载大对象(虚拟代理)
- 控制对敏感资源的访问(保护代理)
- 远程服务本地代理(远程代理)
- 实现日志记录、性能监控等横切关注点
- 实现对象池、缓存等功能
代理模式的优缺点
优点:
- 可以在不修改原始对象的情况下添加额外功能
- 实现了客户端与真实主题的解耦
- 可以灵活控制对真实对象的访问
- 符合开放-封闭原则,易于扩展
缺点:
- 增加了系统复杂度,需要理解代理与真实对象的关系
- 可能导致请求处理速度变慢(多了一层代理)
- 对于复杂代理,实现起来可能比较繁琐
代理模式在C++中有着广泛应用,例如智能指针(std::shared_ptr、std::unique_ptr)就是一种智能引用代理,负责自动管理内存;某些ORM框架中的数据库访问代理也是典型应用。
更多推荐



所有评论(0)