代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用,可以在不改变原始类代码的情况下增加额外的功能。
代理模式的特点
-
控制访问:控制对真实对象的访问
-
附加功能:可以在访问真实对象前后添加额外操作
-
延迟初始化:可以推迟昂贵对象的创建直到真正需要时
-
远程代理:可以代表位于不同地址空间的对象
代理模式的类型
-
虚拟代理:延迟创建开销大的对象
-
保护代理:控制对原始对象的访问权限
-
远程代理:为远程对象提供本地代表
-
智能引用:在访问对象时执行额外操作(如引用计数)
典型应用场景
-
延迟初始化(虚拟代理)
-
访问控制(保护代理)
-
本地代表远程对象(远程代理)
-
日志记录、缓存等附加功能
-
对敏感对象的保护
-
引用计数和内存管理
C++ 示例程序
示例1:虚拟代理(图像加载)
#include <iostream>
#include <string>
#include <memory>
// 抽象主题
class Image {
public:
virtual ~Image() = default;
virtual void display() = 0;
};
// 真实主题
class RealImage : public Image {
private:
std::string filename;
void loadFromDisk() {
std::cout << "Loading image: " << filename << " from disk (expensive operation)\n";
}
public:
RealImage(const std::string& filename) : filename(filename) {
loadFromDisk();
}
void display() override {
std::cout << "Displaying image: " << filename << "\n";
}
};
// 代理类
class ImageProxy : public Image {
private:
std::string filename;
std::unique_ptr<RealImage> realImage;
public:
ImageProxy(const std::string& filename) : filename(filename) {}
void display() override {
if (!realImage) {
realImage = std::make_unique<RealImage>(filename); // 延迟初始化
}
realImage->display();
}
};
// 客户端代码
int main() {
std::cout << "--- Using Proxy ---\n";
ImageProxy proxy("test_image.jpg");
// 图像尚未加载
std::cout << "Image not loaded yet\n";
// 第一次显示 - 加载图像
std::cout << "First display:\n";
proxy.display();
// 第二次显示 - 图像已加载,直接使用
std::cout << "Second display:\n";
proxy.display();
return 0;
}
示例2:保护代理(访问控制)
#include <iostream>
#include <string>
#include <memory>
// 抽象主题
class Database {
public:
virtual ~Database() = default;
virtual void query(const std::string& sql) = 0;
};
// 真实主题
class RealDatabase : public Database {
public:
void query(const std::string& sql) override {
std::cout << "Executing query: " << sql << "\n";
// 实际执行数据库查询...
}
};
// 代理类
class DatabaseProxy : public Database {
private:
std::unique_ptr<RealDatabase> realDb;
std::string userRole;
bool hasAccess() const {
return userRole == "admin";
}
public:
DatabaseProxy(const std::string& role) : userRole(role) {}
void query(const std::string& sql) override {
if (!hasAccess()) {
std::cout << "Access denied for role: " << userRole << "\n";
return;
}
if (!realDb) {
realDb = std::make_unique<RealDatabase>();
}
std::cout << "Log: User " << userRole << " executed query\n";
realDb->query(sql);
}
};
// 客户端代码
int main() {
std::cout << "--- Admin Access ---\n";
DatabaseProxy adminProxy("admin");
adminProxy.query("SELECT * FROM users");
std::cout << "\n--- Guest Access ---\n";
DatabaseProxy guestProxy("guest");
guestProxy.query("DROP TABLE users");
return 0;
}
示例3:智能引用代理(带引用计数)
#include <iostream>
#include <memory>
#include <vector>
// 大型资源类
class ExpensiveResource {
public:
ExpensiveResource() {
std::cout << "Creating expensive resource (high memory usage)\n";
}
~ExpensiveResource() {
std::cout << "Destroying expensive resource\n";
}
void operation() {
std::cout << "Performing operation on expensive resource\n";
}
};
// 智能引用代理
class ResourceProxy {
private:
static ExpensiveResource* realResource;
static int refCount;
public:
ResourceProxy() {
if (refCount == 0) {
realResource = new ExpensiveResource();
}
refCount++;
std::cout << "Resource reference count: " << refCount << "\n";
}
~ResourceProxy() {
refCount--;
std::cout << "Resource reference count: " << refCount << "\n";
if (refCount == 0 && realResource != nullptr) {
delete realResource;
realResource = nullptr;
}
}
ExpensiveResource* operator->() const {
return realResource;
}
};
// 静态成员初始化
ExpensiveResource* ResourceProxy::realResource = nullptr;
int ResourceProxy::refCount = 0;
// 客户端代码
int main() {
std::cout << "--- Using ResourceProxy ---\n";
{
ResourceProxy proxy1;
proxy1->operation();
{
ResourceProxy proxy2;
proxy2->operation();
ResourceProxy proxy3;
proxy3->operation();
} // proxy2和proxy3离开作用域
proxy1->operation();
} // proxy1离开作用域
return 0;
}
示例4:远程代理(模拟)
#include <iostream>
#include <string>
#include <memory>
// 远程服务接口
class PaymentService {
public:
virtual ~PaymentService() = default;
virtual bool processPayment(const std::string& account, double amount) = 0;
};
// 远程服务实现(模拟)
class RemotePaymentService : public PaymentService {
public:
bool processPayment(const std::string& account, double amount) override {
// 模拟远程调用
std::cout << "Connecting to remote payment server...\n";
std::cout << "Processing payment of $" << amount << " to account " << account << "\n";
// 模拟网络延迟
std::cout << "Waiting for response...\n";
return true; // 假设总是成功
}
};
// 远程代理
class PaymentServiceProxy : public PaymentService {
private:
std::unique_ptr<RemotePaymentService> realService;
public:
bool processPayment(const std::string& account, double amount) override {
if (!realService) {
realService = std::make_unique<RemotePaymentService>();
}
// 可以在这里添加缓存、日志等功能
std::cout << "Proxy: Logging payment request - "
<< account << ", $" << amount << "\n";
bool result = realService->processPayment(account, amount);
std::cout << "Proxy: Payment processed, result: "
<< (result ? "success" : "failure") << "\n";
return result;
}
};
// 客户端代码
int main() {
std::cout << "--- Using Payment Proxy ---\n";
PaymentServiceProxy proxy;
proxy.processPayment("ACCT-12345", 100.0);
proxy.processPayment("ACCT-67890", 250.0);
return 0;
}
总结
代理模式通过引入一个代理对象来控制对原始对象的访问,其主要优点包括:
-
控制访问:可以在访问对象前后添加额外操作
-
延迟初始化:对于资源密集型对象,可以推迟创建直到真正需要时
-
远程代理:可以简化远程对象的访问
-
保护机制:可以增加权限检查等安全层
代理模式与装饰器模式的区别在于:
-
代理控制访问,通常管理其服务对象的生命周期
-
装饰器为对象添加行为,通常不控制对象的生命周期
在实际应用中,代理模式常用于:
-
延迟加载大型资源
-
实现访问控制
-
本地代表远程服务
-
添加日志、缓存等横切关注点