结构型模式--代理
1、意图
为其他对象提供一种代理以控制对这个对象的访问。
2、结构
3、参与者
Proxy:
保存一个引用使得代理可以访问实体。若RealSubject和Subject的接口相同,Proxy会引用Subject。
提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。
控制对实体的存取,并可能负责创建和删除它。
其他功能依赖于代理的类型:远程代理负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求;虚代理可以缓存实体的附加信息,以便延迟对它的访问;保护代理检查调用者是否具有实现一个请求所必须的访问权限。
Subject:定义RealSubject和Proxy的共有接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
RealSubject:定义Proxy所代表的实体。
4、适用性
在需要用比较通用和复杂的对象指针代替简单地指针的时候,使用Proxy模式。下面是可以使用代理模式常见的情况:
远程代理:为一个对象在不同的地址空间提供局部代表。
虚代理:根据需要创建开销很大的对象。
保护代理:控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
智能引用:取代了简单的指针,它在访问对象时执行一些附加操作。它的典型用途包括:
对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它(智能指针);
当第一次引用一个持久对象时,将它装入内存;
在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。
5、代码示例
// Virtual 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接口用来显示图像文件。Image重定义HandleMouse操作,使得用户可以交互的调整图像的尺寸。 class Image : public Graphic { public: Image(const char* file);// loads image from a file virtual ~Image(); 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); private: // ... }; // ImageProxy和Image具有相同的接口: class ImageProxy : public Graphic { public: Imageproxy(const char* imageFile); 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;// don't know extent yet _image = 0; } Image* Imageproxy::GetImage() { if (_image == 0) { _image = new Image(_fileName); } return _image; } // 如果可能的话,GetExtent的实现部分返回缓存的图像尺寸;否则从文件中装载图像。Draw用来装载图像,HandelMouse则向实际图像转发这个事件。 const Point& ImageProxy::GetExtent () { if(_extent == Point::Zero) { _extent = GetImage()->GetExtent(); } return _extent; } void ImageProxy::Draw (const Point& at) { GetImage()->Draw(at); } void ImageProxy::HandleMouse (Event& event) { GetImage()->HandleMouse(event ); } // Save操作将缓存的图像尺寸和文件名保存在一个流中。Load得到这个信息并初始化相应的成员函数。 void ImageProxy::Save (ostream& to) { to <<_extent <<_fileName; } void ImageProxy::Load (istream& from) { from >>_extent >>_fileName; }
// 最后,假设我们有一个类TextDocument能够包含Graphic对象 class TextDocument { public: TextDocument () void Insert (Graphic*); // ... }; // 我们可以用以下方式把ImageProxy插入到文本文件中。 TextDocument* text = new TextDocument; // ... text->Insert (new ImageProxy("anImageFileName"));
6、总结
代理模式通过代理类控制用户对实体的访问,这种控制可以是访问权限的控制,可以是在原访问的基础上附加一些额外的信息或处理。用户直接访问的对象是代理而不是真实实体。
代理模式分为远程代理、虚代理、保护代理、智能引用。
代理模式中的Porxy与RealSubject,即代理与真实实体,需提供一致的对外接口,这些接口在基类Subject中声明。
本文来自博客园,作者:流翎,转载请注明原文链接:https://www.cnblogs.com/hjx168/p/16218830.html