设计模式(12) 代理模式(PROXY)
2014-02-10 08:51
344 查看
问题聚焦:
这个模式是对象结构型模式的最后一个。学习完就可以进入下一种类型的模式了。
代理模式的主要目的:控制对某个对象的访问(如通过拒绝某些访问实现访问权限的控制,或进行加载等耗时操作的优化)。
意图:
为其他对象提供一种代理以控制对这个对象的访问。
别名:
Surrogate
动机:
原因:为了只有在我们确实需要这个对象时才对它进行创建和初始化,因此对一个对象进行访问控制。
Demo:文档编辑器
需求:可以在文档中嵌入图形对象
挑战:有些图形对象的创建开销很大,但是打开文档必须很迅速,因此我们再打开文档时应避免一次性创建所有开销很大的对象。因此,并非所有这些文档中都同时可见,所以也没有必要同时创建这些对象。
方案:对于一个开销很大的对象,应该根据需要进行创建,当一个图像变为可见时,会产生这样的需求。这时,使用一个图像Proxy替代那个真正的图像,在需要的时候负责实例化这个图像对象。
只有当文档编辑器激活图像代理的Draw操作以显示这个图像的时候,图像Proxy才创建真正的图像。
实现:
文件名作为对实际对象的引用。
代理存储了图像的尺寸(extent)
文档编辑器通过抽象的Graphic类定义的接口访问嵌入的图像。ImageProxy是图像代理类。
ImageProxy保存了文件名作为指向磁盘上的图像文件的指针,该文件名作为一个参数传递给ImageProxy
ImageProxy还存储了这个图像的边框以及对真正的Image实例的指引,直到代理实例化真正图像时,这个指引才有效。
ImageProxy操作只有在图像被实例化后,才向它传递请求。
类图:
适用性:
通常,在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy。
下面是一些可以使用Proxy模式的常见情况:
远程代理:为一个对象在不同的地址空间提供局部代理
虚代理:根据需要创建开销很大的对象,在上一节提到的ImageProxy就是这样一种代理的例子。
保护代理:控制对原始对象的访问。用于对象应该有不同的访问权限的时候。
智能指引:取代了简单的指针,它在访问对象时执行一些附加操作(引用计数,装入内存,加锁)。
结构:
在运行时刻一种可能的代理结构的对象图如下所示:
参与者:
Proxy(ImageProxy):
保存一个引用使得代理可以访问实体。
提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体
控制对实体的存取,并可能负责创建和删除它
Subject(Graphic):
定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy
RealSubject(Image):
定义Proxy所代表的实体
协作:
代理根据其种类,在适当的时候向RealSubject转发请求。
效果:
Proxy模式在访问对象时,引入了一定程度的间歇性(一个中间层),在这个中间层中,可以做一些附加动作或者优化。
Copy-on-write优化:对用户隐藏,发生在中间层的优化。
优化场景:拷贝一个庞大而复杂的对象,开销很大,如果这个拷贝根本没有被修改,那么这些开销就没有必要。
方案:用Proxy对象延迟这一拷贝过程,我们可以当只有这个对象被修改的时候才对它进行拷贝。
实现:在进行c-o-w优化时,必须对实体继续拧引用计数,当引用数目为零时,实体将被删除。
效果:可以大幅度的降低拷贝庞大实体时的开销
实现:
Proxy可以利用一下一些语言特性:
重载C++中的存取运算符:将代理对象作为实际对象的一个指针使用(重载->和*操作符)
Proxy并不总是需要知道实体的类型:若Proxy类能够完全通过一个抽象接口处理它的实体,则无需为每一个实际对象类都生成一个代理类。该Proxy可以统一处理所有的实际对象。但是如果代理对象需要实例化实际对象,那么它必须知道具体的类。
代理示例:
以上面提到的文本编辑器为例,实现虚代理:
Graphic类为图形对象定义一个接口
类设定完毕,我们可以通过下面的方式把ImageProxy插入到文本文件中
相关模式:
适配器模式:为它所适配的对象提供一个不同的接口。代理模式则提供了与实际对象基本相同的接口(因为访问保护的代理可能会拒绝执行实际对象的操作,所以它的接口实际上可能是实体接口的一个子集)。
装饰器模式:目的不一样,装饰器为对象添加一个或多个功能,而代理模式则控制对象的访问。
参考资料:
《设计模式:可复用面向对象软件的基础》
这个模式是对象结构型模式的最后一个。学习完就可以进入下一种类型的模式了。
代理模式的主要目的:控制对某个对象的访问(如通过拒绝某些访问实现访问权限的控制,或进行加载等耗时操作的优化)。
意图:
为其他对象提供一种代理以控制对这个对象的访问。
别名:
Surrogate
动机:
原因:为了只有在我们确实需要这个对象时才对它进行创建和初始化,因此对一个对象进行访问控制。
Demo:文档编辑器
需求:可以在文档中嵌入图形对象
挑战:有些图形对象的创建开销很大,但是打开文档必须很迅速,因此我们再打开文档时应避免一次性创建所有开销很大的对象。因此,并非所有这些文档中都同时可见,所以也没有必要同时创建这些对象。
方案:对于一个开销很大的对象,应该根据需要进行创建,当一个图像变为可见时,会产生这样的需求。这时,使用一个图像Proxy替代那个真正的图像,在需要的时候负责实例化这个图像对象。
只有当文档编辑器激活图像代理的Draw操作以显示这个图像的时候,图像Proxy才创建真正的图像。
实现:
文件名作为对实际对象的引用。
代理存储了图像的尺寸(extent)
文档编辑器通过抽象的Graphic类定义的接口访问嵌入的图像。ImageProxy是图像代理类。
ImageProxy保存了文件名作为指向磁盘上的图像文件的指针,该文件名作为一个参数传递给ImageProxy
ImageProxy还存储了这个图像的边框以及对真正的Image实例的指引,直到代理实例化真正图像时,这个指引才有效。
ImageProxy操作只有在图像被实例化后,才向它传递请求。
类图:
适用性:
通常,在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy。
下面是一些可以使用Proxy模式的常见情况:
远程代理:为一个对象在不同的地址空间提供局部代理
虚代理:根据需要创建开销很大的对象,在上一节提到的ImageProxy就是这样一种代理的例子。
保护代理:控制对原始对象的访问。用于对象应该有不同的访问权限的时候。
智能指引:取代了简单的指针,它在访问对象时执行一些附加操作(引用计数,装入内存,加锁)。
结构:
在运行时刻一种可能的代理结构的对象图如下所示:
参与者:
Proxy(ImageProxy):
保存一个引用使得代理可以访问实体。
提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体
控制对实体的存取,并可能负责创建和删除它
Subject(Graphic):
定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy
RealSubject(Image):
定义Proxy所代表的实体
协作:
代理根据其种类,在适当的时候向RealSubject转发请求。
效果:
Proxy模式在访问对象时,引入了一定程度的间歇性(一个中间层),在这个中间层中,可以做一些附加动作或者优化。
Copy-on-write优化:对用户隐藏,发生在中间层的优化。
优化场景:拷贝一个庞大而复杂的对象,开销很大,如果这个拷贝根本没有被修改,那么这些开销就没有必要。
方案:用Proxy对象延迟这一拷贝过程,我们可以当只有这个对象被修改的时候才对它进行拷贝。
实现:在进行c-o-w优化时,必须对实体继续拧引用计数,当引用数目为零时,实体将被删除。
效果:可以大幅度的降低拷贝庞大实体时的开销
实现:
Proxy可以利用一下一些语言特性:
重载C++中的存取运算符:将代理对象作为实际对象的一个指针使用(重载->和*操作符)
Proxy并不总是需要知道实体的类型:若Proxy类能够完全通过一个抽象接口处理它的实体,则无需为每一个实际对象类都生成一个代理类。该Proxy可以统一处理所有的实际对象。但是如果代理对象需要实例化实际对象,那么它必须知道具体的类。
代理示例:
以上面提到的文本编辑器为例,实现虚代理:
Graphic类为图形对象定义一个接口
class Graphic { public: virtual ~Graphic(); virtual void Draw(const Point& at) = 0; virtual void HandleMouse( Event& event) = 0; virtual const Point& GetExtent() = 0; virtual void Load(istream& from) = 0; virtual void Save(ostream& to) = 0; protected: Graphic(); }; // Image类实现了Graphic接口用来显示图像文件的接口。 // 同时,实现了Handlemouse操作,使得用户可以交互第调整图像的尺寸。 class Image : public Graphic { public: Image(const char* file); virtual void Draw(const Point& at); virtual void HandleMouse( Event& event); virtual const Point& GetExtent(); virtual void Load(istream& from); virtual void Save(ostream& to); protected: // .... } // ImageProxy和Image具有相同的接口 class ImageProxy : public Graphic { public: virtual ~ImageProxy(); virtual void Draw(const Point& at); virtual void HandleMouse( Event& event); virtual const Point& GetExtent(); virtual void Load(istream& from); virtual void Save(ostream& to); protected: Image* GetImage(); private: Image* _image; Point _extent; char* _fileName; }; // 构造函数保存了存储图像的文件名的本地拷贝,并初始化_extent和_image ImageProxy::ImageProxy (const char* fileName) { _fileName = strdup(fileName); _extent = Point::Zero; _image = 0; } Image* ImageProxy::GetImage() { if (_image == 0) { _image = new Image(_fileName); } } // GetExtent返回缓存的图像尺寸,否则从文件中装载图像。 const Point& ImageProxy::GetExtent () { if (_extent == Point::Zero) { _extent = GetImage()->GetExtent(); } return _extent; } // Draw用来装载图像 void ImageProxy::Draw (const Point& at) { GetImage()->Draw(at); } // HandleMouse void ImageProxy::HandleMouse (Event& event) { GetImage()->HandleMouse(event); } // Save操作将缓存的图像尺寸和文件名保存在一个流中 void ImageProxy::Save (ostream& to) { to << _extent << _fileName; } // Load得到这个信息并初始化相应的成员函数 void ImageProxy::Load (istream& from) { from >> _extent >> _fileName; } // 假设有一个client,包含Graphic对象 class TextDocument { public: TextDocument(); void Insert(Graphic*); };
类设定完毕,我们可以通过下面的方式把ImageProxy插入到文本文件中
TextDocument* text = new TextDocument; // ... text->Insert(new ImageProxy("anImageFileName"));
相关模式:
适配器模式:为它所适配的对象提供一个不同的接口。代理模式则提供了与实际对象基本相同的接口(因为访问保护的代理可能会拒绝执行实际对象的操作,所以它的接口实际上可能是实体接口的一个子集)。
装饰器模式:目的不一样,装饰器为对象添加一个或多个功能,而代理模式则控制对象的访问。
参考资料:
《设计模式:可复用面向对象软件的基础》
相关文章推荐
- 【设计模式 - 12】之代理模式(Proxy)
- 设计模式(12)——代理(Proxy)模式
- 设计模式12---设计模式之代理模式(Proxy)(结构型)
- 设计模式(12)--Proxy(代理模式)--结构型
- 设计模式(12)-结构型-代理模式(Proxy)
- 设计模式12--代理模式(Proxy)
- 设计模式12: Proxy 代理模式(结构型模式)
- 【设计模式 - 12】之代理模式(Proxy)
- [设计模式] 12 代理模式 proxy
- 设计模式12 - 代理模式 Proxy
- 设计模式之(六)代理模式Proxy
- 设计模式----代理模式(Proxy)
- 设计模式:代理模式(Proxy)
- 设计模式之代理(proxy)模式
- 设计模式 --- 代理模式(Proxy) 精选经验合集
- Java设计模式之结构型模式-代理模式(Proxy)
- 设计模式之Proxy(代理)
- 设计模式(十一)代理模式Proxy(结构型)
- 设计模式(4):proxy(代理)