初探代理模式
代码链接
koonchen/design-patterns/proxy
要点
为其他对象提供一种代理以控制这个对象的访问。
当我们打开某个图形编辑器的时候,很多图形对象的创建开销很大,但是打开它需要很迅速,所以应该按需创建。我们如何才能隐藏根据需要创建图像这一事实,从而不会让编辑器的实现复杂化?
问题的解决是使用另外一个对象,即图像 Proxy ,代替那个真正的图像。 Proxy 可以代替一个图像对象,并且在需要时负责实例化图像对象。
代理模式的适用性:
远程代理:为一个对象在不同的地址空间提供局部代表。
虚代理:根据需要创建开销很大的对象。
保护代理:控制对原始对象的访问。保护代理用于对象应该有不同访问权限的时候。
智能指引:取代了简单的指针,它在访问对象时执行了一些附加操作:
- 对指向实际对象的引用计数,这样当该对象没有引用的时候,可以自动释放它。
- 当第一次引用一个持久对象时,将它装入内存。
- 在访问一个实际对象前,检查时候已经锁定了它,以确保其他对象不能改变它。
代理模式的参与者:
- Proxy — 保存一个引用使得代理可以访问实体。代替实体,同时它控制对实体的读取、创建、删除。
- Subject — 定义 RealSubject 和 Proxy 的共用接口,这样就在任何使用 RealSubject 的地方都可以使用 Proxy 了。
- RealSubject — 定义 Proxy 所代表的实体。
现在,代理模式已经显而易见了,结构如下:
Proxy 模式在访问对象时引入了一定程度的间接性,根据代理的类型,附加了很多用途:
- Remote Proxy 可以隐藏一个对象存在于不同地址空间的事实。
- Virtual Proxy 可以进行最优化,例如根据要求创建对象。
- Protection Proxies 和 Smart Reference 都允许在访问一个对象时有一些附加的内务处理。
需要注意的是,还有一种被称为 copy-on-write 的优化方式,该优化根据需要创建的对象有关,用代理延迟拷贝的过程,因为它没有被修改的时候,没有必要因为拷贝而产生开销。只有用户请求修改实体的操作时,代理才会真正拷贝它。
实现
Proxy 模式可以利用以下一些语言特性:
- 重载 C++ 中的存取运算符。
- 使用 Smalltalk 中的 doesNotUnderstand , Smalltalk 提供一个 hook 方法可以用来自动转发请求。当用户向接受者发送一个消息, Proxy 可以重定义 doesNotUnderstand 以便它的实体转发这个消息。
- Proxy 并不总是需要知道实体的类型,若 Proxy 类能够完全通过一个抽象接口处理它的实体,则无需为每一个 RealSubject 都生成一个 Proxy 类, Proxy 类统一处理所有的 RealSubject 类。当然,如果是实例化,那么是需要知道具体类的。
Java 实现
1 | interface Subject { |
python 实现
1 | class Subject(object): |
实现异曲同工,不再赘述。
相关模式:
- Adapter :适配器为它所适配的对象提供了一个不同的接口。相反的,代理提供了与它实体相同的接口。
- Decoratro :它和 Proxy 很像,但是目的不同,Decorator 为对象添加一个或多个功能,而代理则控制对对象的访问。