C++设计模式-代理(4)

设计模式:在解决某一类问题场景时,有既定的,优秀的代码框架可以直接使用,其优势如下:

  • 代码更易于维护,代码的可读性,复用性,可移植性,健壮性会更好
  • 当软件原有需求有变更或者增加新的需求时,合理的设计模式的应用,能够做到软件设计要求的开-闭原则,即对修改关闭,对扩展开放,使软件原有功能修改,新功能扩充非常灵活
  • 合理的设计模式的选择,会使软件设计更加模块化,积极的做到软件设计遵循的根本原则高内聚,低耦合

软件设计开-闭原则

开闭原则是软件设计中的一个重要原则,指的是软件实体(如类、模块、函数等)应该对扩展开放,对修改关闭。这意味着在不修改现有代码的基础上,通过扩展新功能来满足新的需求,从而提高软件的灵活性和可维护性

对扩展开放:允许在现有系统中添加新功能

对修改关闭:不需要修改现有的代码来添加新功能,避免引入新错误

通过遵循开闭原则,可以提高代码的可复用性和稳定性。常用的方法包括使用抽象类、接口以及多态等技术

结构型设计模式

结构型设计模式关注类和对象的组合,旨在通过继承或接口来实现更大的结构(继承的概念被用来组合接口和定义组合对象获得新功能的方式)。这些模式帮助确保系统各部分之间的良好组织和交互。以下是一些常见的结构型设计模式

适配器模式(Adapter Pattern)

桥接模式(Bridge Pattern)

组合模式(Composite Pattern)

装饰器模式(Decorator Pattern)

外观模式(Facade Pattern)

享元模式(Flyweight Pattern)

代理模式(Proxy Pattern)



一、代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问为委托类(访问对象)提供了一种代理以控制客户对委托类对象(访问对象)的访问权限)。代理模式可以在不改变客户端代码的情况下增加对实际对象的访问控制

主要角色

抽象主题(Subject)–公共基类:声明真实对象和代理对象的共同接口(声明各类抽象接口)

真实主题(Real Subject)–委托类:实现抽象主题(实现所有抽象接口),定义代理对象所代表的真实对象

代理(Proxy):持有真实对象(委托类实例对象)的引用,并实现抽象主题接口,控制对真实对象的访问


1.示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <iostream>
#include <memory>

using namespace std;

/***********************抽象公共基类***********************/
// 声明了各种抽象接口
class VideoSite
{
public:
// 可以观看免费电影
virtual void freeMovie() = 0;
// 可以观看VIP电影
virtual void vipMovie() = 0;
// 可以观看用券电影
virtual void ticketMovie() = 0;
};
/***********************抽象公共基类***********************/


/***********************委托类***********************/
// 委托类继承子抽象公共基类,实现各种抽象接口
class FixBugVideoSite:public VideoSite
{
public:
virtual void freeMovie()
{
cout << "观看免费电影" << endl;
}
virtual void vipMovie()
{
cout << "观看VIP电影" << endl;
}
virtual void ticketMovie()
{
cout << "观看用券电影" << endl;
}
};
/***********************委托类***********************/


/***********************代理类1(控制免费用户对委托类的访问权限)***********************/
class FreeVideoSiteProxy:public VideoSite
{
public:
FreeVideoSiteProxy(){
// 委托类对象实例
pVideo = new FixBugVideoSite();
}
~FreeVideoSiteProxy()
{
delete pVideo;
}

// 实现抽象接口
virtual void freeMovie()
{
// 通过代理类的freeMovie来访问真正委托类对象的freeMovie
pVideo->freeMovie();
}
virtual void vipMovie()
{
// 免费用户无VIP电影的观看权限
cout << "观看VIP电影,需要升级为VIP用户" << endl;
}
virtual void ticketMovie()
{
// 免费用户无用券电影的观看权限
cout << "观看用券电影,需要购买券" << endl;
}
private:
// 抽象公共基类指针,指向委托类的对象
// 指向基类的引用/指针可引用派生类对象不需要显示转换
VideoSite *pVideo;
};
/***********************代理类1(控制免费用户对委托类的访问权限)***********************/


/***********************代理类2(控制VIP用户对委托类的访问权限)***********************/
class vipVideoSiteProxy:public VideoSite
{
public:
vipVideoSiteProxy(){
// 委托类对象实例
pVideo = new FixBugVideoSite();
}
~vipVideoSiteProxy()
{
delete pVideo;
}

// 实现抽象接口
virtual void freeMovie()
{
// 通过代理类的freeMovie来访问真正委托类对象的freeMovie
pVideo->freeMovie();
}
virtual void vipMovie()
{
// 通过代理类的vipMovie来访问真正委托类对象的vipMovie
pVideo->vipMovie();
}
virtual void ticketMovie()
{
// 免费用户无用券电影的观看权限
cout << "观看用券电影,需要购买券" << endl;
}
private:
// 抽象公共基类指针,指向委托类的对象
// 指向基类的引用/指针可引用派生类对象不需要显示转换
VideoSite *pVideo;
};
/***********************代理类2(控制VIP用户对委托类的访问权限)***********************/


void watchMovie(unique_ptr<VideoSite> &ptr)
{
ptr->freeMovie();
ptr->vipMovie();
ptr->ticketMovie();
}

int main()
{
unique_ptr<VideoSite> p1(new FreeVideoSiteProxy());
unique_ptr<VideoSite> p2(new vipVideoSiteProxy());

watchMovie(p1);
watchMovie(p2);

return 0;
}

总结:代理模式,通过代理类,对委托类进行代理,来控制客户对实际对象(委托类对象)的访问权限。委托类与代理类均从同一个抽象公共基类继承而来

代理模式通过在真实对象前增加一个代理对象,控制对真实对象的访问,提供额外的功能和灵活性。适用于需要控制对象访问、延迟对象创建或实现远程访问的场景

image-20240701113403567


2.代理模式的类型

远程代理(Remote Proxy):为一个对象在不同的地址空间提供局部代表。可以隐藏对象存在于不同地址空间的事实

虚拟代理(Virtual Proxy):根据需要创建开销较大的对象,通过它来存放实例化需要很长时间的真实对象

保护代理(Protection Proxy):控制对原始对象的访问。用于对象应该有不同的访问权限的时候

智能指引(Smart Reference):取代了简单的指针,它在访问对象时执行一些附加操作


3.优缺点

优点:

控制对真实对象的访问:可以在访问前后进行预处理或后处理

增加系统的灵活性:可以在不修改客户端代码的情况下,引入新的代理类型

实现远程代理:可以让客户端访问远程对象,就像访问本地对象一样

缺点:

增加系统复杂性:引入代理对象会增加系统的复杂度

性能开销:代理模式可能会引入一些额外的性能开销,尤其是在需要频繁访问真实对象时

适用场景

需要控制对象的访问:如对对象的访问进行权限控制、记录日志、延迟加载等

需要创建开销较大的对象:可以通过虚拟代理延迟对象的创建,直到需要时才创建

需要远程访问对象:通过远程代理,客户端可以访问位于不同地址空间的对象