【c++设计模式15】结构型7:代理模式(Proxy Pattern)
- 一、定义
- 二、适用场景
- 三、过程
- 四、代理模式类图
- 五、C++示例代码
- 六、使用注意事项
- 七、结论
类型 | 序号 | 设计模式 | 描述 |
结构型 | 1 | 适配器模式 (Adapter Pattern) | 它用于在不修改已有类的情况下,将其接口转换为客户端所期望的接口。 |
2 | 桥接模式 (Bridge Pattern) | 实现了抽象化与实现化的脱耦。他们两个互相独立,不会影响到对方。 | |
3 | 组合模式 (Composite Pattern) | 将对象组合成树状结构来表示“部分-整体”的层次结构。 | |
4 | 装饰模式 (Decorator Pattern) | 它允许你在不改变现有对象结构的情况下,动态地将责任(功能)附加到对象上。 | |
5 | 外观模式 (Facade Pattern) | 对一个子系统的接口.它提供了一个简化的接口,用于访问复杂系统中的一组接口。 | |
6 | 享元模式 (Flyweight Pattern) | 对象的存储开销,它通过共享对象来减少内存使用和提高性能 | |
7 | 代理模式 (Proxy Pattern) | 它提供了一个代理类来控制对于原始对象的访问 |
一、定义
代理模式(Proxy Pattern)是一种结构型设计模式,它提供了一个代理类来控制对于原始对象的访问。代理类和原始类实现相同的接口,客户端通过代理类间接地访问原始对象,从而可以在不改变原始对象的情况下,通过扩展代理类来添加额外的功能或控制访问。
二、适用场景
代理模式适用于以下情况:
- 当需要限制对于原始对象的访问权限时,可以使用代理模式来进行访问控制。
- 当需要在访问原始对象前后执行额外的操作时,可以使用代理模式来添加附加功能,如日志记录、性能监控等。
- 当原始对象处于远程服务器上,通过本地代理进行网络通信时,可以使用代理模式来将底层的复杂性隐藏起来。
三、过程
代理模式的过程包括以下几个步骤:
- 定义接口:定义原始对象和代理类共同实现的接口,以确保代理类可以替代原始对象。
- 实现原始类:实现接口的原始对象,即被代理的对象。该对象通常是具有业务逻辑的核心类。
- 实现代理类:实现接口的代理类,它持有一个原始对象的引用,并在必要时调用原始对象的方法。代理类可以在调用原始对象方法前后执行额外的操作,或者在不需要访问原始对象时,返回缓存的结果。
- 客户端使用代理对象:客户端通过代理对象来间接访问原始对象,无需直接与原始对象进行交互。
四、代理模式类图
如果我们想要用代理模式来描述一下电话虫的行为,里边有如下几个细节:
- 网络代理是一个对象,真实网络也是一个对象,网络代理模拟的是真实网络
- 网络代理和真实网络有相同的行为,所以需要为二者提供一个抽象类
- 真实网络是在为网络代理办事,所以网络代理和真实网络应该有关联关系。
根据上面的描述,先把对应的UML类图画一下:
五、C++示例代码
以下是一个使用代理模式的示例代码,在这个示例中,我们将以网络访问为例,展示如何使用代理模式来控制对于网络资源的访问:
#include <iostream>
// 抽象主题:网络访问
class NetworkAccess {
public:
virtual void request(const std::string& url) = 0;
};
// 真实主题:实际进行网络访问
class RealNetworkAccess : public NetworkAccess {
public:
void request(const std::string& url) override {
std::cout << "真实主题:访问网址 " << url << std::endl;
}
};
// 代理类:网络访问代理
class NetworkAccessProxy : public NetworkAccess {
private:
RealNetworkAccess* realAccess;
public:
void request(const std::string& url) override {
if (realAccess == nullptr) {
realAccess = new RealNetworkAccess();
}
// 在访问真实主题之前可以执行额外操作
std::cout << "代理类:检查权限" << std::endl;
realAccess->request(url);
// 在访问真实主题之后可以执行额外操作
std::cout << "代理类:记录日志" << std::endl;
}
};
int main() {
NetworkAccess* network = new NetworkAccessProxy();
network->request("https://www.example.com");
delete network;
return 0;
}
输出
在上述示例中,我们定义了抽象主题 NetworkAccess,它声明了一个 request() 方法来进行网络访问。具体的网络访问类 RealNetworkAccess 实现了该接口,并提供了实际的网络访问功能。
代理类 NetworkAccessProxy 实现了 NetworkAccess 接口,它持有一个 RealNetworkAccess 的实例,并在调用实际网络访问前后执行额外的操作,如权限检查和日志记录。
在 main 函数中,我们通过创建代理对象 NetworkAccessProxy 来间接访问网络资源。代理对象在执行网络访问之前会先进行权限检查,然后调用真实主题对象的 request() 方法,最后记录访问日志。
六、使用注意事项
代理模式增加了间接性,可能会导致系统复杂化。需要谨慎设计和使用,避免过多的代理类。
代理模式可以提供额外的功能或控制访问,但可能会引入性能损失。需要权衡是否值得在访问中引入额外开销。
对于频繁创建的代理对象,可以考虑使用享元模式来减少内存占用。
注意线程安全性,特别是当多个线程同时访问代理对象时。
注意事项:
1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
七、结论
通过测试程序我们可以得到如下结论:如果使用代理模式,不能改变所代理的类的接口,使用代理模式的目的是为了加强控制。