Proxy 代理模式,为其它对象提供一种代理以控制这个对象的访问。客户代码与代理类打交道,而做实际工作的类隐藏在代理类背后。当调用代理类中的一个函数时,代理类仅转而去调用实现中相应的函数。
在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用 Proxy 代理模式。Proxy 适用于以下情况:
1.远程代理(Remote Proxy)为一个对象在不同的地址空间提供局部代表。比如要操作一个网络上的一个对象(网络性能不好时,问题尤其突出),这时应该将这个问题交给代理去完成。
2.虚代理(Virtual Proxy)根据需要创建开销很大的对象,将这个创建的过程交给代理去完成。
3.保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4.智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。主要用途包括:1)对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它(也称智能指针 Smart Pointer)。2)当第一次引用一个持久对象时,将它装入内存。3)在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。
Proxy 代理模式的通用结构如下:
参与者:
Proxy:保存一个引用使得代理可以访问实体。若 RealSubject 和 Subject 的接口相同,Proxy 会引用 Subject。提供一个与 Subject 的接口相同的接口,这样代理就可以用来代替实体。控制对实体的存取,并可能负责创建和删除它。其它功能依赖于代理的类型:远程代理,负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求。虚代理,可以缓冲实体的附加信息,以便延迟对它的访问。保护代理,检查调用者是否有实现一个请求所必需的访问权限。
Subject:定义 RealSubject 和 Proxy 的共用接口,这样就在任何使用 RealSubject 的地方都可以使用 Proxy。
RealSubject:定义 Proxy 所代表的实体。
Proxy 代理根据其种类,在适当的时候向 RealSubject 转发请求。
效果:Proxy 模式在访问对象时引入了一定程度的间接性。Remote Proxy 可以隐藏一个对象存在于不同地址空间的事实。Virtual Proxy 可以进行最优化,例如根据需要创建对象。Protection Proxy 和 Smart Reference 都允许在访问一个对象时有一些附加的内务处理。
Proxy 模式还可以对用户隐藏“写时拷贝:copy-on-wirte”的优化方式,该优化根据需要创建对象。在实现 copy-on-write 时必须对实体进行引用计数。拷贝代理仅会增加引用计数。只有当用户请求一个修改该实体的操作时,代理才会真正拷贝它。在这种情况下,代理还必须减少实体的引用计数。当引用的数目为零时,这个实体将被删除。Copy-on-Write 可以大幅度的降低拷贝庞大实体时的开销。
Proxy 代理模式示例代码:
1:
2: #pragma once
3: #include <iostream>
4:
5: // 定义了 Proxy 和 RealSubject 的公有接口,
6: // 这样就可以在任何需要使用到 RealSubject 的地方都使用 Proxy.
7: class Subject
8: {
9: public:
10: Subject(){}
11: virtual ~Subject(){}
12:
13: virtual void Request() = 0;
14: };
15:
16: // 真正使用的实体
17: class RealSubject : public Subject
18: {
19: public:
20: RealSubject()
21: {
22: std::cout << "Constructing a RealSubjectc." << std::endl;
23: }
24: virtual ~RealSubject(){}
25:
26: virtual void Request()
27: {
28: std::cout << "Request By RealSubject." << std::endl;
29: }
30: };
31:
32: // 代理类,含有一个指向RealSubject对象的指针
33: class Proxy : public Subject
34: {
35: public:
36: Proxy() : m_pRealSubject(NULL)
37: {
38: std::cout << "Constructing a Proxy." << std::endl;
39: }
40: virtual ~Proxy()
41: {
42: delete m_pRealSubject;
43: m_pRealSubject = NULL;
44: }
45:
46: virtual void Request()
47: {
48: // 需要使用RealSubject的时候才去初始化
49: if (NULL == m_pRealSubject)
50: {
51: std::cout << "Request By Proxy." << std::endl;
52: m_pRealSubject = new RealSubject();
53: }
54: m_pRealSubject->Request();
55: }
56:
57:
58: private:
59: RealSubject* m_pRealSubject;
60: };
//test
1:
2: #include "Proxy.h"
3:
4: int main()
5: {
6: Subject* pProxy = new Proxy();
7: pProxy->Request();
8:
9: delete pProxy;
10:
11: return 0;
12: }
设计模式一书给出的代码示例:
虚代理示例,根据需要创建大对象时使用
1: //虚代理示例:
2: class Image;
3: extern Image* LoadAnImageFile(const char*);
4:
5: //ImagePtr 相当于 Proxy
6: class ImagePtr
7: {
8: public:
9: ImagePtr(const char* imageFile)
10: : _imageFile(imageFile), _image(0)
11: { }
12: virtual ~ImagePtr();
13:
14: //重载 -> 和 * 运算符使用 LoadImage 将 _image 返回给它的调用者。
15: virtual Image* operator->()
16: {
17: return LoadImage(); /
18: }
19: virtual Image& operator*()
20: {
21: return *LoadImage(); //
22: }
23:
24: private:
25: Image* LoadImage()
26: {
27: if(_image = 0)
28: _image = LoadAnImageFile(_imageFile);
29: return _image;
30: }
31: private:
32: Image* _image;
33: const char* _imageFile;
34: };
35:
36: //该方法使你能够通过 ImagePtr 对象调用 Image 操作,而省去了把这些操作作为
37: //ImagePtr 接口的一部分的麻烦。
38: ImagePtr image = ImagePtr("anImageFileName");
39: image->Draw(Point(50,100));
40: //即 (image.operator->())->Draw(Point(50,100));
41: //请注意这里的 image 代理起到一个指针的作用,但并没有将它定义一个指向 Image 的指针。
42: //这意味着你不能把它当作一个真正的指向 Image 的指针来使用。因此在使用此方法时用户
43: //应区别对待 Image 对象和 ImagePtr 对象。