Proxy

代理

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。被代理的对象可以是远程的对象、创建开销大的对象或需要安全控制的对象。

适用性

  • 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。下面是一些可以使用Proxy模式常见情况:
  1. 远程代理(Remote Proxy)为一个对象在不同的地址空间提供局部代表。
  2. 虚代理(Virtual Proxy)根据需要创建开销很大的对象。
  3. 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
  4. 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。典型用途如:对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它(Smart Pointers);当第一次引用一个持久对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。
  5. 防火墙代理(Firewall Proxy)控制网络资源的访问,保护主题免于“坏客户”的侵害。
  6. 缓存代理(Caching Proxy)为开销大的运算结果提供暂时存储;它也允许多个客户共享结果,以减少计算或网络延迟。常用于Web服务器代理,以及内容管理与出版系统。
  7. 同步代理(Synchronization Proxy)在多线程的情况下为主题提供安全的访问。
  8. 复杂隐藏代理(Complexity Hiding Proxy)用来隐藏一个类的复杂几何的复杂度,并进行访问控制。有时候也成为外观代理(Facade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。
  9. 写入时复制代理(Copy-On-Write Proxy)用来控制对象的复制,方法是延迟对象的复制,知道客户真的需要为止。这是虚拟代理的变体。

结构

Proxy Class
Proxy Class2
Proxy Object

远程代理

Remote Proxy

虚拟代理

Virtual Proxy

Proxy

  • 保存一个引用使得代理可以访问实体。若RealSubject和Subject的接口相同,Proxy会引用Subject。
  • 提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。
  • 控制对实体的存取,并可能负责创建和删除它。
  • 其他功能依赖于代理的类型:

Remote Proxy负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求。
Virtual Proxy可以缓存实体的附加信息,以便延迟对它的访问。如ImageProxy缓存图像实体的尺寸。
Protection Proxy检查调用者是否具有实现一个请求所必须的访问权限。

Subject - 定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
RealSubject - 定义Proxy所代表的实体。

协作:
代理根据其种类,在适当的时候向RealSubject转发请求。

实现

Virtual Proxy

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
// Example of Virtual Proxy
#include <iostream>
#include <string>
//---------------------------------------------------
class Subject
{
public:
virtual std::string request(){return "";}
};
//---------------------------------------------------
class RealSubject : public Subject
{
public:
RealSubject():Subject()
{
std::cout<<"RealSubject Create Once"<<std::endl;
}
virtual std::string request()
{

return std::string("I'm Real!");
}
};
//---------------------------------------------------
class Proxy : public Subject
{
public:
Proxy(): Subject(), m_summary(""), m_real(NULL) {}
virtual std::string request()
{

if (m_summary.empty())
{
m_summary = get_real_subject()->request(); // creat RealSubject only when needed.
}
return m_summary;
}
RealSubject* get_real_subject()
{

if (!m_real) m_real = new RealSubject();
return m_real;
}
private:
RealSubject* m_real;
std::string m_summary;
};
//---------------------------------------------------
class Client
{
public:
void print_summary(Subject* s)
{

std::cout<<s->request()<<std::endl;
}
};
//---------------------------------------------------
int main()
{

Client s;
Proxy p;
s.print_summary(&p);
s.print_summary(&p);
system("Pause");
}

相关模式

  • Adapter:适配器Adapter为它所适配的对象提供了一个不同的接口。相反,代理提供了与它的实体相同的接口。然而,用于访问保护的代理可能会拒绝执行实体会执行的操作,因此,它的接口实际上可能只是实体接口的一个子集。
  • Decorator:尽管decorator的实现部分与代理相似,但decorator的目的不一样。Decorator为对象添加一个或多个功能,而代理则控制对对象的访问。

[1] 设计模式:可复用面向对象软件的基础
[2] Head First 设计模式