已同步到公众号:【蚂蚁博士军团】【码蚁软件】
前言:
今天一起来了解一下结构型设计模式:代理模式
一、原理、示例代码
代理模式是一种结构型设计模式,它允许你提供一个代理(或者占位符)以控制对其他对象的访问。使用代理模式,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
代理模式的主要目的是控制对对象的访问,而不是直接访问它。这种控制可以是对访问的限制,也可以是对访问的增强。
在代理模式中,有三个角色:
-
Subject(主题):定义了 RealSubject 和 Proxy 的共同接口,这样在任何使用 RealSubject 的地方都可以使用 Proxy。
-
RealSubject(真实主题):定义了 Proxy 所代表的真实对象。
-
Proxy(代理):保存一个引用使得代理可以访问实体,并提供一个与 Subject 的接口相同的接口,这样代理可以用来替代实体。
下面是一个使用C++实现的代理模式的示例代码:
#include <iostream>
#include <string>
// 主题接口
class Subject {
public:
virtual void request() = 0;
};
// 真实主题
class RealSubject : public Subject {
public:
void request() override {
std::cout << "RealSubject: Handling request." << std::endl;
}
};
// 代理
class Proxy : public Subject {
private:
RealSubject* realSubject;
public:
void request() override {
if (realSubject == nullptr) {
realSubject = new RealSubject();
}
std::cout << "Proxy: Logging request." << std::endl;
realSubject->request();
}
};
int main() {
Proxy proxy;
proxy.request();
return 0;
}
在上面的示例中,Subject 是主题接口,RealSubject 是真实主题,Proxy 是代理。当客户端调用代理的 request() 方法时,代理会在调用真实主题之前执行日志记录等操作。
二、结构图
代理模式的结构图如下所示:
+--------------+ +--------------+ +--------------+
| Subject | | RealSubject | | Proxy |
+--------------+ +--------------+ +--------------+
| +request() | | +request() | | +request() |
+--------------+ +--------------+ +--------------+
| |
+--------------+
在这个结构中,Subject 是主题接口,定义了真实主题和代理的公共接口。RealSubject 是真实主题,实现了主题接口,并定义了代理所代表的真实对象。Proxy 是代理,实现了主题接口,并保存了一个指向真实主题的引用,以便可以在需要时访问真实主题。当客户端需要访问真实主题时,可以通过代理来访问。代理可以在访问真实主题之前或之后执行一些额外的操作,例如记录日志、验证权限等。
三、使用场景:
代理模式通常在以下场景中被使用:
-
远程代理(Remote Proxy):用于在不同地址空间中代表对象。这种情况下,代理对象充当本地对象的代表,隐藏了远程对象的存在。
-
虚拟代理(Virtual Proxy):用于按需创建昂贵对象。当对象的创建和初始化需要大量资源时,可以使用代理对象来延迟对象的创建,直到客户端真正需要使用它时才创建。
-
保护代理(Protection Proxy):用于控制对对象的访问。代理可以对客户端的请求进行过滤和验证,以确保客户端有合适的权限来访问真实对象。
-
缓存代理(Cache Proxy):用于为开销大的运算结果提供暂时的存储。代理可以在调用真实对象之前检查缓存,如果缓存中存在请求的结果,则直接返回缓存中的数据,否则调用真实对象来计算结果,并将结果存入缓存。
-
日志记录(Logging):代理可以在调用真实对象的方法前后进行日志记录,以实现日志功能而不需要修改真实对象的代码。
总之,代理模式适用于需要控制对对象的访问、延迟对象的创建、提供缓存或日志记录等功能的情况。
使用场景的一些示例代码:
下面是一个使用C++实现代理模式进行日志记录的示例代码:
#include <iostream>
#include <string>
// 接口类
class Subject {
public:
virtual void request() = 0;
};
// 真实主题类
class RealSubject : public Subject {
public:
void request() override {
std::cout << "RealSubject: 处理请求" << std::endl;
}
};
// 代理类
class Proxy : public Subject {
private:
RealSubject* realSubject;
public:
Proxy() : realSubject(new RealSubject()) {}
void request() override {
// 在调用真实主题前记录日志
std::cout << "Proxy: 记录日志 - 请求开始" << std::endl;
// 调用真实主题
realSubject->request();
// 在调用真实主题后记录日志
std::cout << "Proxy: 记录日志 - 请求结束" << std::endl;
}
};
int main() {
Proxy proxy;
proxy.request();
return 0;
}
在这个示例中,Subject
是一个接口类,RealSubject
是实际的处理类,Proxy
是代理类。当调用 Proxy
的 request
方法时,它会在调用真实主题前后记录日志,然后再调用真实主题的 request
方法来处理请求。这样就实现了代理模式用于日志记录的功能。
下面是一个使用C++实现远程代理的示例代码:
#include <iostream>
#include <string>
// 接口类
class Subject {
public:
virtual void request() = 0;
};
// 远程主题类
class RemoteSubject : public Subject {
public:
void request() override {
std::cout << "RemoteSubject: 处理远程请求" << std::endl;
}
};
// 代理类
class Proxy : public Subject {
private:
RemoteSubject* remoteSubject;
public:
Proxy() : remoteSubject(nullptr) {}
void request() override {
if (remoteSubject == nullptr) {
// 创建远程对象
remoteSubject = new RemoteSubject();
}
// 在调用远程主题前进行网络连接等操作
std::cout << "Proxy: 进行网络连接" << std::endl;
// 调用远程主题
remoteSubject->request();
// 在调用远程主题后进行网络关闭等操作
std::cout << "Proxy: 关闭网络连接" << std::endl;
}
};
int main() {
Proxy proxy;
proxy.request();
return 0;
}
在这个示例中,Subject
是一个接口类,RemoteSubject
是远程的处理类,Proxy
是代理类。当调用 Proxy
的 request
方法时,它会在调用远程主题前进行网络连接等操作,然后调用远程主题的 request
方法来处理远程请求,最后再进行网络关闭等操作。这样就实现了代理模式中的远程代理功能。
下面是一个使用C++实现代理模式的示例代码,演示了虚拟代理的场景:
#include <iostream>
#include <string>
// 接口类
class Image {
public:
virtual void display() = 0;
};
// 真实主题类
class RealImage : public Image {
private:
std::string filename;
public:
RealImage(const std::string& filename) : filename(filename) {
// 模拟加载图片的过程
std::cout << "RealImage: 加载图片 " << filename << std::endl;
}
void display() override {
std::cout << "RealImage: 显示图片 " << filename << std::endl;
}
};
// 代理类
class ProxyImage : public Image {
private:
std::string filename;
RealImage* realImage;
public:
ProxyImage(const std::string& filename) : filename(filename), realImage(nullptr) {}
void display() override {
if (realImage == nullptr) {
// 创建真实图片对象
realImage = new RealImage(filename);
}
realImage->display();
}
};
int main() {
// 使用代理对象加载和显示图片
Image* image = new ProxyImage("example.jpg");
image->display();
return 0;
}
在这个示例中,Image
是一个接口类,RealImage
是真实的图片处理类,ProxyImage
是代理类。当创建 ProxyImage
对象时,并调用 display
方法时,它会在需要显示图片时才去创建真实的图片对象,从而实现了虚拟代理的延迟加载功能。
下面是一个使用C++实现保护代理的示例代码,演示了保护代理的场景:
#include <iostream>
#include <string>
// 接口类
class Door {
public:
virtual void open() = 0;
virtual void close() = 0;
};
// 真实主题类
class RealDoor : public Door {
public:
void open() override {
std::cout << "RealDoor: 打开门" << std::endl;
}
void close() override {
std::cout << "RealDoor: 关闭门" << std::endl;
}
};
// 代理类
class SecurityDoor : public Door {
private:
RealDoor* realDoor;
bool isAdmin;
public:
SecurityDoor(bool isAdmin) : realDoor(new RealDoor()), isAdmin(isAdmin) {}
void open() override {
if (isAdmin) {
realDoor->open();
} else {
std::cout << "SecurityDoor: 没有权限打开门" << std::endl;
}
}
void close() override {
if (isAdmin) {
realDoor->close();
} else {
std::cout << "SecurityDoor: 没有权限关闭门" << std::endl;
}
}
};
int main() {
// 创建安全门对象
Door* door = new SecurityDoor(true); // 使用管理员权限
door->open();
door->close();
Door* guestDoor = new SecurityDoor(false); // 使用普通访客权限
guestDoor->open();
guestDoor->close();
return 0;
}
在这个示例中,Door
是一个接口类,RealDoor
是真实的门处理类,SecurityDoor
是代理类。在 SecurityDoor
中,根据权限的不同,决定是否允许打开或关闭门。当使用管理员权限时,可以打开和关闭门;当使用普通访客权限时,无法打开或关闭门,从而实现了保护代理的功能。
四、优缺点:
优点:
-
代理模式可以实现对真实主题的远程控制,例如在网络上的远程代理。
-
代理模式可以实现对真实主题的保护,例如控制对真实主题的访问权限。
-
代理模式可以实现对真实主题的增强,例如在调用真实主题的方法前后进行一些额外的操作。
缺点:
-
增加了系统复杂性,因为引入了代理对象。
-
由于在代理模式中会引入代理对象,可能会导致请求的处理速度变慢。
欢迎有更多朋友一起探讨技术哈,评论区留言~