Proxy 代理對象結構模式

     Proxy 代理模式,爲其它對象提供一種代理以控制這個對象的訪問。客戶代碼與代理類打交道,而做實際工作的類隱藏在代理類背後。當調用代理類中的一個函數時,代理類僅轉而去調用實現中相應的函數。

     在需要用比較通用和複雜的對象指針代替簡單的指針的時候,使用 Proxy 代理模式。Proxy 適用於以下情況:

1.遠程代理(Remote Proxy)爲一個對象在不同的地址空間提供局部代表。比如要操作一個網絡上的一個對象(網絡性能不好時,問題尤其突出),這時應該將這個問題交給代理去完成。

2.虛代理(Virtual Proxy)根據需要創建開銷很大的對象,將這個創建的過程交給代理去完成。

3.保護代理(Protection Proxy)控制對原始對象的訪問。保護代理用於對象應該有不同的訪問權限的時候。

4.智能指引(Smart Reference)取代了簡單的指針,它在訪問對象時執行一些附加操作。主要用途包括:1)對指向實際對象的引用計數,這樣當該對象沒有引用時,可以自動釋放它(也稱智能指針 Smart Pointer)。2)當第一次引用一個持久對象時,將它裝入內存。3)在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其它對象不能改變它。

Proxy 代理模式的通用結構如下:

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 對象。
發佈了54 篇原創文章 · 獲贊 3 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章