C++ 代理模式实现
外观
代理模式(Proxy Pattern)是设计模式中的一种结构型模式,它通过提供一个代理对象来控制对另一个对象的访问。代理模式常用于延迟初始化、访问控制、日志记录等场景。在C++中,代理模式通常通过接口继承和组合来实现。
简介[编辑 | 编辑源代码]
代理模式的核心思想是为其他对象提供一种代理,以控制对这个对象的访问。代理对象可以在客户端和目标对象之间起到中介的作用,从而在不修改目标对象代码的情况下增加额外的功能。
代理模式的主要角色包括:
- Subject(抽象主题):定义真实主题和代理主题的共同接口。
- RealSubject(真实主题):实现抽象主题的具体业务逻辑。
- Proxy(代理):持有对真实主题的引用,控制对真实主题的访问。
实现方式[编辑 | 编辑源代码]
以下是代理模式在C++中的典型实现方式:
1. 静态代理[编辑 | 编辑源代码]
静态代理在编译时就已经确定代理关系。
#include <iostream>
#include <string>
// 抽象主题
class Image {
public:
virtual void display() = 0;
virtual ~Image() = default;
};
// 真实主题
class RealImage : public Image {
public:
RealImage(const std::string& filename) : filename_(filename) {
loadFromDisk();
}
void display() override {
std::cout << "Displaying " << filename_ << std::endl;
}
private:
void loadFromDisk() {
std::cout << "Loading " << filename_ << " from disk" << std::endl;
}
std::string filename_;
};
// 代理
class ProxyImage : public Image {
public:
ProxyImage(const std::string& filename) : filename_(filename), realImage_(nullptr) {}
void display() override {
if (realImage_ == nullptr) {
realImage_ = new RealImage(filename_);
}
realImage_->display();
}
~ProxyImage() {
delete realImage_;
}
private:
std::string filename_;
RealImage* realImage_;
};
// 客户端代码
int main() {
Image* image = new ProxyImage("test.jpg");
// 第一次访问会加载图片
image->display();
// 第二次访问直接显示图片
image->display();
delete image;
return 0;
}
输出结果:
Loading test.jpg from disk Displaying test.jpg Displaying test.jpg
2. 动态代理[编辑 | 编辑源代码]
C++本身不直接支持动态代理(如Java的Proxy类),但可以通过模板和运行时多态实现类似效果。
类图[编辑 | 编辑源代码]
以下是代理模式的类图表示:
应用场景[编辑 | 编辑源代码]
代理模式在以下场景中特别有用:
1. 虚拟代理:延迟创建开销大的对象(如图片加载)。 2. 保护代理:控制对原始对象的访问权限。 3. 远程代理:为位于不同地址空间的对象提供本地代表。 4. 智能引用:在访问对象时执行额外操作(如引用计数、锁检查)。
实际案例[编辑 | 编辑源代码]
考虑一个银行账户系统,我们可能希望添加访问控制:
#include <iostream>
#include <string>
class BankAccount {
public:
virtual void withdraw(int amount) = 0;
virtual ~BankAccount() = default;
};
class RealBankAccount : public BankAccount {
public:
void withdraw(int amount) override {
std::cout << "Withdrew $" << amount << " from account" << std::endl;
}
};
class SecureBankAccountProxy : public BankAccount {
public:
SecureBankAccountProxy(const std::string& user) : user_(user), realAccount_(nullptr) {}
void withdraw(int amount) override {
if (checkAccess()) {
if (realAccount_ == nullptr) {
realAccount_ = new RealBankAccount();
}
realAccount_->withdraw(amount);
} else {
std::cout << "Access denied for user: " << user_ << std::endl;
}
}
~SecureBankAccountProxy() {
delete realAccount_;
}
private:
bool checkAccess() {
// 简单的权限检查
return user_ == "admin";
}
std::string user_;
RealBankAccount* realAccount_;
};
int main() {
BankAccount* adminAccount = new SecureBankAccountProxy("admin");
BankAccount* userAccount = new SecureBankAccountProxy("user");
adminAccount->withdraw(100); // 允许
userAccount->withdraw(50); // 拒绝
delete adminAccount;
delete userAccount;
return 0;
}
输出结果:
Withdrew $100 from account Access denied for user: user
优缺点[编辑 | 编辑源代码]
优点:
- 可以在不修改目标对象的情况下增加功能
- 职责清晰,符合单一职责原则
- 可以实现对象的延迟加载
- 可以控制对目标对象的访问
缺点:
- 可能会增加系统的复杂度
- 在客户端和目标对象之间增加了代理层,可能会影响性能
与其他模式的关系[编辑 | 编辑源代码]
- 适配器模式:改变被适配对象的接口,而代理模式保持相同的接口。
- 装饰器模式:增强对象的功能,而代理模式控制对对象的访问。
- 外观模式:为一组接口提供统一接口,而代理模式为单个对象提供替代接口。
总结[编辑 | 编辑源代码]
代理模式是C++中一种非常有用的设计模式,它通过引入代理对象来控制对原始对象的访问。这种模式特别适用于需要控制对象访问、延迟加载或添加额外功能的场景。理解并掌握代理模式可以帮助开发者编写更加灵活和可维护的代码。