[學習筆記]設計模式之Proxy

爲方便讀者,本文已添加至索引:html

寫在前面

「魔鏡啊魔鏡,誰是這個世界上最美麗的人?」 每到晚上,女王都會問魔鏡相同的問題(見Decorator模式)。這是她還曾身爲女巫時留下的習慣。儘管要提及這個心裏邪惡的女巫,將會有一大堆故事,但咱們今天要討論的主角,倒是這面神奇的鏡子。關於魔鏡的來歷,誰都不是很清楚。就連這個世界的創造者魔導士(見Builder模式)也對它的存在感到好奇。魔鏡可以迴應主人的訴求,回答主人所提出的問題,並透過鏡子來提示答案相關的信息。咱們能夠經過時の魔導士的研究手札來依稀瞭解下這個神祕的魔法造物。程序員

「這面魔鏡能夠顯現出我所創造的這個世界中任何的物體,這頗有趣。」設計模式

「……可是它彷佛也僅僅是提供了一種受限制的訪問對象的方式,由於我不能經過它直接接觸到對象自己。」函數

「……它也僅在我須要的時候纔會顯示出對應的物體,我相信它並不是從誕生之時就存儲好了世界上全部物體的影像。」學習

「……魔鏡在顯示答案時更像是一種採用了Proxy模式的造物優化

是的,他提到了Proxy(代理),一種設計模式。在繼續深刻研究魔鏡以前,咱們先來了解下Proxy的大體內容。ui

要點梳理

  • 目的分類
    • 對象結構型模式
  • 範圍準則
    • 對象(該模式處理對象間的關係,這些關係在運行時刻是能夠變化的,更具動態性)
  • 主要功能
    • 爲其餘對象提供一種代理以控制對這個對象的訪問
  • 適用狀況
    • 在須要用比較通用和複雜的對象指針代替簡單的指針的時候,使用Proxy。
    • 遠程代理(Remote Proxy):爲一個對象在不一樣的地址空間提供局部表明
    • 虛代理(Virtual Proxy):根據須要建立開銷很大的對象
    • 保護代理(Protection Proxy):控制對原始對象的訪問
    • 智能指引(Smart Reference):取代了簡單的指針,它在訪問對象時執行一些附加操做。好比:對指向實際對象的引用計數,這樣當該對象沒有引用時,能夠自動釋放它;在訪問一個實際對象前,檢查是否已經鎖定了它,以確保其餘對象不能改變它等等。
  • 參與部分
    • Proxy:保存一個引用使得代理能夠訪問實體;提供一個與Subject的接口相同的接口,用來替代實體;控制對實體的存取,並可能負責建立和刪除它;
    • Subject:定義RealSubject和Proxy的共用接口,這樣就在任何使用RealSubject的地方均可以使用Proxy
    • RealSubject:定義Proxy所表明的實體
  • 協做過程
    • 代理根據其種類,在適當的時候向RealSubject轉發請求。
  • UML圖例

示例分析 - 無所不知的魔鏡

 

 

 

 

 

 

 

爲了更加深刻地瞭解魔鏡,咱們先回顧一個知識點:在Decorator模式筆記中,咱們瞭解到一個全部可見物體的抽象類VisualObject。從鏡子之中,咱們能夠看到某個對象的影像Image
spa

1 class Image : public VisualObject {
2 public:
3     Image(string name);     // load an image.
4     virtual ~Image();
5     
6     virtual void show();
7 }

然而透過魔鏡,咱們能夠看到任何想看東西的Image。如前文所述,不可能讓魔鏡在一開始就把全部的Image都實例化。(換成咱們程序員的思惟,就是會形成存儲開銷過於巨大),怎麼辦?Proxy模式給出了一種解決策略。讓咱們看看所謂的ImageProxyMagic吧:設計

 1 class ImageProxyMagic : public VisualObject {
 2 public:
 3     ImageProxyMagic(string name);       // Just save the name.
 4     virtual ~Image();
 5     
 6     virtual void show();
 7 protected:
 8     Image* getImage();
 9 private:
10     string _name;
11     Image* _image;
12 }

誒,有沒有發現它對外的接口和Image相同?是的,這樣一來咱們就能夠像操做Image同樣,操做ImageProxyMagic了。可是具體它又作了什麼?看看代碼吧:代理

 1 ImageProxyMagic::ImageProxyMagic(string name) {
 2     _name = name;
 3     _image = 0;
 4 }
 5 
 6 Image* ImageProxyMagic::getImage() {
 7     if (!_image) {
 8         _image = new Image(_name);
 9     }
10     return _image;
11 }
12 
13 void ImageProxyMagic::show() {
14     getImage()->show();
15 }

注意到,構造函數存儲了Image的名字,而將Image的裝載過程延緩到getImage函數當中。於是,只有在某個Image真正須要show出來的時候,它纔會被裝載。ImageProxyMagic將show命令轉發給Image處理。

儘管如此,咱們仍是不瞭解魔鏡爲何會知道問題的答案,咱們僅僅看到的它在展現答案時候的一個可能處理方式。咱們不由想對它提出這樣一個問題:

「魔鏡啊魔鏡,你爲何無所不知?」

特色總結

使用Proxy模式在訪問對象時引入了必定程度的間接性。根據代理的類型,附加的間接性也有多種用途:

  1. Remote Proxy能夠隱藏一個對象存在於不一樣地址空間的事實。
  2. Virtual Proxy能夠進行最優化,例如根據要求建立對象。
  3. Protectoin Proxy和Smart Reference都容許在訪問一個對象時有一些附加的內務處理。

Proxy模式並不老是須要知道實體的類型。若是Proxy類可以徹底經過一個抽象接口處理它的實體,則無須爲每個RealSubject類都生成一個Proxy類;但若是Proxy要實例化RealSubject的話,(好比咱們的例子中)那它必須知道具體的類。

寫在最後

今天的筆記就到這裏了,歡迎你們批評指正!若是以爲能夠的話,好文推薦一下,我會很是感謝的!

相關文章
相關標籤/搜索