定义
代理模式(Proxy Pattern) 是一种结构型设计模式,它通过提供一个代理对象来控制对目标对象的访问。代理对象作为客户端与目标对象之间的中介,间接地访问目标对象的功能。代理模式可以在不改变目标对象的情况下增加一些额外的功能,如延迟加载、安全控制、日志记录等。
基本思想
代理对象:代理模式引入了一个中介对象(代理对象)来访问真实的对象。代理对象控制对真实对象的访问,并可以在访问真实对象之前或之后加入额外的功能。
目标对象:代理模式的核心是需要被代理的对象,它实现了实际的业务逻辑。
客户端:客户端通过代理对象间接调用目标对象的方法,而不直接访问目标对象。
适用场景
代理模式适用于以下场景:
- 控制访问:当需要控制对某个对象的访问时,可以使用代理模式。比如,代理模式可以限制某些操作,或者在目标对象没有初始化时,延迟加载目标对象。
- 延迟加载:在需要时才创建目标对象,而不是在系统初始化时创建,这样可以节省资源。
- 缓存:通过代理模式,代理对象可以缓存目标对象的结果,避免重复计算。
- 日志记录:代理对象可以在方法执行前后记录日志,确保目标对象的行为被正确监控。
- 远程访问:代理模式可用于实现远程访问对象,客户端与代理对象交互,而代理对象负责与远程目标对象进行通信。
类设计
代码实现解析
- 设计目标:代理模式实现任务处理
我们设计一个简单的场景,其中 ISubject 是任务处理接口,RealSubject 是具体的任务处理类,SubjectProxy 是代理类,它负责对 RealSubject 的间接访问。
#include <iostream>
#include <string>
using namespace std;
// 定义Subject接口
class ISubject {
public:
virtual void process() = 0;
virtual ~ISubject() {}
};
// 真实主题类(RealSubject)
class RealSubject : public ISubject {
public:
void process() override {
cout << "RealSubject: Processing the task." << endl;
}
};
// 代理类(SubjectProxy)
class SubjectProxy : public ISubject {
private:
RealSubject* realSubject;
public:
SubjectProxy() : realSubject(nullptr) {}
void process() override {
// 代理对象在访问目标对象之前做一些处理(如延迟加载、权限检查等)
cout << "Proxy: Checking access rights..." << endl;
if (!realSubject) {
// 延迟加载目标对象
realSubject = new RealSubject();
cout << "Proxy: Creating RealSubject instance..." << endl;
}
// 代理对象调用真实主题的方法
realSubject->process();
}
~SubjectProxy() {
delete realSubject; // 确保释放真实主题对象的资源
}
};
// 客户端类
class ClientApp {
private:
ISubject* subject;
public:
ClientApp() {
subject = new SubjectProxy(); // 客户端通过代理类访问任务
}
void DoTask() {
// 客户端通过代理对象执行任务
subject->process();
}
~ClientApp() {
delete subject;
}
};
int main() {
ClientApp app;
app.DoTask(); // 通过代理对象处理任务
return 0;
}
输出:
Proxy: Checking access rights...
Proxy: Creating RealSubject instance...
RealSubject: Processing the task.
客户端通过 ClientApp 调用 subject->process(),
但实际执行的是通过 SubjectProxy 代理对象的 process() 方法。
代理对象首先检查访问权限(这里是模拟操作),
然后如果目标对象尚未创建,则延迟创建 RealSubject 实例并执行任务。
类设计分析
1.ISubject(接口/抽象类):
- 定义了代理类和真实对象共同的接口。在本例中,process() 方法是客户端与代理类和真实类交互的唯一方式。
2.RealSubject(真实主题):
- RealSubject 是实际执行任务的类,它提供了业务逻辑的实现。
- 在 process() 方法中,RealSubject 处理实际的任务。
3.SubjectProxy(代理类):
- 代理类实现了 ISubject 接口,负责控制对 RealSubject 的访问。代理类可以在调用 RealSubject 的方法之前执行一些操作(如延迟加载、权限验证、日志记录等)。
- 在 process() 方法中,代理对象会检查是否已经创建了 RealSubject 实例,如果没有,则创建一个实例并调用 process()。
4.ClientApp(客户端):
- 客户端通过 ISubject 接口与 SubjectProxy(代理对象)交互,而不直接与 RealSubject 进行交互。客户端只调用 process() 方法,而无需关心代理对象如何处理目标对象的访问。
代理模式的优缺点
优点:
- 控制访问:代理模式可以控制对目标对象的访问,并增加附加功能,如懒加载、日志、权限验证等。
- 提高效率:通过延迟加载(懒加载),可以在需要时才创建目标对象,从而节省资源。
- 解耦:客户端不需要直接与目标对象交互,代理类充当了客户端和目标对象之间的中介,降低了系统的耦合性。
- 附加功能:可以在代理类中为目标对象添加额外的功能,如缓存、日志、权限检查等,而不修改目标对象的代码。
缺点
- 增加复杂度:代理模式通过引入额外的类增加了系统的复杂度,特别是在目标对象复杂时。
- 性能开销:代理类通常会引入一定的性能开销,尤其是在频繁的代理操作中,可能会影响系统的性能。
- 不可避免的代理层:代理模式在某些情况下可能导致不必要的中间层,尤其是当目标对象的接口已经足够简洁时。
适用场景
代理模式适用于以下场景:
- 延迟加载:当对象的创建成本较高时,可以使用代理模式进行延迟加载。
- 访问控制:当需要对目标对象的访问进行控制时(如权限验证、缓存等),可以使用代理模式。
- 资源保护:代理模式可用于保护目标对象的资源,如防止频繁创建和销毁实例。
- 远程代理:在分布式系统中,代理模式可以用来控制客户端与远程对象之间的通信。
常见应用场景:
- 虚拟代理:延迟加载目标对象,直到真正需要它时才创建实例。
- 保护代理:限制客户端对某些操作的访问,进行权限检查。
- 远程代理:客户端通过代理与远程对象进行交互,代理负责与远程服务器通信。
- 智能代理:增加一些额外的功能,如缓存、日志、事务管理等。
总结
代理模式通过引入代理类,允许客户端通过代理间接访问目标对象,并能在不改变目标对象的情况下,增加一些额外的功能,如延迟加载、访问控制、日志记录等。代理模式能有效地解耦客户端和目标对象,简化客户端与目标对象之间的交互,同时增加系统的灵活性。