目录
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一个代理以控制对这个对象的访问。代理模式的主要目的是在客户端和目标对象之间增加一层间接访问,从而可以在访问目标对象之前或之后添加额外的操作。
代理模式的关键组成部分
- 主题接口(Subject Interface):定义了真实对象和代理对象共同遵循的接口。
- 真实对象(Real Subject):实现了主题接口,提供了最终的业务逻辑。
- 代理对象(Proxy):也实现了主题接口,但它不直接提供真实的业务逻辑,而是通过委托给真实对象来间接提供服务,并在请求前后可以添加额外的操作。
代理模式的应用场景
代理模式适用于以下情况:
- 在访问一个对象时需要附加额外的操作,比如权限检查、日志记录、事务处理等。
- 控制对一个对象的访问,简化客户端对真实对象的引用。
- 当一个对象需要一个代理来控制其访问时。
代理模式的实现步骤
- 定义主题接口。
- 实现真实对象类。
- 实现代理对象类,并在适当的时候委托给真实对象。
代理模式的示例
假设我们要创建一个图像显示类,但由于图像文件可能比较大,直接加载会消耗较多资源,因此我们先创建一个代理对象,只有在真正需要显示图像时才加载图像。
步骤1:定义主题接口
c
深色版本
1#include <stdio.h>
2#include <stdlib.h>
3
4typedef struct Image {
5 void (*display)(struct Image *);
6} Image;
7
8void displayImage(Image *image) {
9 image->display(image);
10}
步骤2:实现真实对象类
c
深色版本
1typedef struct RealImage {
2 char *filename;
3} RealImage;
4
5RealImage* createRealImage(const char *filename) {
6 RealImage *realImage = (RealImage *)malloc(sizeof(RealImage));
7 realImage->filename = strdup(filename);
8 loadFromDisk(realImage);
9 return realImage;
10}
11
12void loadFromDisk(RealImage *realImage) {
13 printf("Loading image from disk: %s\n", realImage->filename);
14}
15
16void displayRealImage(RealImage *realImage) {
17 printf("Displaying %s\n", realImage->filename);
18}
19
20void destroyRealImage(RealImage *realImage) {
21 free(realImage->filename);
22 free(realImage);
23}
步骤3:实现代理对象类
c
深色版本
1typedef struct ProxyImage {
2 char *filename;
3 RealImage *realImage;
4} ProxyImage;
5
6ProxyImage* createProxyImage(const char *filename) {
7 ProxyImage *proxyImage = (ProxyImage *)malloc(sizeof(ProxyImage));
8 proxyImage->filename = strdup(filename);
9 proxyImage->realImage = NULL;
10 return proxyImage;
11}
12
13void displayProxyImage(ProxyImage *proxyImage) {
14 if (proxyImage->realImage == NULL) {
15 proxyImage->realImage = createRealImage(proxyImage->filename);
16 }
17 displayRealImage(proxyImage->realImage);
18}
19
20void destroyProxyImage(ProxyImage *proxyImage) {
21 if (proxyImage->realImage != NULL) {
22 destroyRealImage(proxyImage->realImage);
23 }
24 free(proxyImage->filename);
25 free(proxyImage);
26}
步骤4:客户端代码
c
深色版本
1int main() {
2 Image *proxyImage = (Image *)createProxyImage("example.jpg");
3 proxyImage->display = displayProxyImage;
4
5 displayImage(proxyImage); // 第一次调用时加载图像
6 displayImage(proxyImage); // 再次调用时不再加载
7
8 destroyProxyImage((ProxyImage *)proxyImage);
9
10 return 0;
11}
运行结果
当你运行上述 main
函数时,你会看到以下输出:
深色版本
1Loading image from disk: example.jpg
2Displaying example.jpg
3Displaying example.jpg
解释
在这个例子中,ProxyImage
是 RealImage
的代理。当我们第一次调用 displayImage
方法时,代理会检查是否已经加载了真实的图像,如果没有,则加载图像。此后再调用 displayImage
方法时,代理就会直接使用已经加载的图像。
代理模式的优点
- 职责分离:代理模式使得职责更加清晰,客户端只需关心访问接口,而不用关心实际的加载逻辑。
- 延迟加载:通过代理模式可以实现延迟加载(Lazy Loading),即在真正需要时才加载资源。
- 控制访问:可以在代理中添加任何必要的逻辑,例如权限检查、日志记录等。
代理模式的缺点
- 增加复杂度:引入代理对象增加了系统的复杂度。
- 性能开销:在某些情况下,代理模式可能会增加额外的性能开销,尤其是在频繁创建和销毁代理对象时。
总结
代理模式通过为真实对象提供一个代理对象来控制对真实对象的访问。它适用于需要在访问对象时附加额外操作的情况,或者需要延迟加载资源的情况。代理模式可以帮助我们更好地组织代码,并提供更强大的控制机制。在设计系统时,可以根据需要选择是否使用代理模式来增强系统的灵活性和可扩展性。