代理模式與Android

來源:互聯網
上載者:User

標籤:設計模式   代理模式   智能指標   代碼設計實現   android   

代理模式(Proxy)


一、   什麼是代理模式

先來看看官方的說法,代理模式就是為其他對象提供一種代理,以控制對這個對象的訪問。

 

看來這個官方的說法的確有點官方,看了還是讓人感覺不點不知所措,還是不明白代理模式是什麼,究竟是用來做什麼的。

 

其實代理這個名詞,對於我們來說其實並不陌生,生活中有很多關於代理的例子。例如校園代理等,就以校園代理來講,這個校園代理就是為他對應的上司的作代理,而這個校園代理的工作就是訪問校園中的學生,例如對學生進行問卷之類的事。在這個例子中,學生就是官方說法中的其他對象,校園代理的上司就通過控制這個校園代理來控制對學生的訪問。這下應該明白一點了吧。


二、   代理模式的類圖

 


三、   代理模式的實現代碼(C++實現)

以上面說的校園代理為例子,我們來一睹代理模式的風采,為了更好地理解這個模式,還是要作一點的解釋的。在下面的代碼中,將出現三個類,Worker、Boss和SchoolProxy,他們分別對應的Subject、RealSubject和Proxy這三個類,而這些類中的doSurvey方法,就是相當於中的Request方法。

 

註:其實只是一個代理模式的UML模型圖,Request其實是代表著所有Proxy和RealSubject的共用介面,而不僅僅是這裡所寫的一個。

 

其實現代碼如下(proxy.cpp):

1、Worker類的定義如下,它有一個doSurvey的介面

class Worker{public:     virtual void doSurvey() = 0;     virtual ~Worker(){}};

2、Boss類定義如下,它繼承Worker類,並實現doSurvey介面

class Boss : public Worker{public:     virtual void doSurvey()     {        cout << "The ABCDE company do sruvey!" << endl;     }};

3、SchoolProxy類定義如下,它同樣繼承Worker類,並實現doSurvey介面,該類維護一個Boss類的對象的引用,並在它的中doSurvey方法中調用Boss的doSurvey方法。

class SchoolProxy : public Worker{public:     SchoolProxy():        _boss(NULL)     {     }     virtual ~SchoolProxy()     {        if(_boss != NULL)        {            delete _boss;        }     }     SchoolProxy(const SchoolProxy&proxy)     {        _boss = newBoss(*proxy._boss);     }     SchoolProxy& operator=(const SchoolProxy &rhs)     {        if(this != &rhs)        {            SchoolProxytmp_proxy(rhs);            Boss *tmp_boss =tmp_proxy._boss;            tmp_proxy._boss = _boss;            _boss = tmp_boss;        }        return *this;     }     virtual void doSurvey()     {        if(_boss == NULL)        {            _boss = new Boss();        }        _boss->doSurvey();     }private:     Boss *_boss;};

註:此類中的Boss也可不使用指標,而直接使用對象。但是因為java或C#這類的語言並不支援棧上對象,所有的對象都是new出來的,所以這樣的寫法與java和C#更相似。

 

4、調用方法如下:

int main(){SchoolProxy *proxy = new SchoolProxy();proxy->doSurvey();delete proxy;return 0;}
從上面的代碼,我們可以清晰地看到,校園代理SchoolProxy是如何協助它的Boss來完成做調查的工作的。

 

四、   代理模式的應用

看了上面的代碼,我想代理模式的操作和原理,大家都差不多可以理解了,但是其實代理還是有不只一種的,根據通常的使用,可以分為四類。

 

1)            遠程代理

它為一個對象在不同的地址空間提供局部代表。這樣就可以隱藏一個對象存在於不同地址空間的事實,它的例子就是WebServer。

2)            虛擬代理

它根據需求建立開銷比較大的對象,通過它來存放執行個體化需要很長時間的真實對象。例如,當我們瀏覽網頁時,網頁中可能有一些比較大的圖片,雖然圖片比較大,但是你還是可以很快地開啟網頁,然而圖片卻不能在第一時間顯示,可能要在幾秒後才能正常顯示,在這裡就是通過虛擬代理來替換真實的圖片。

3)            保護代理

它用於控制對原對象的訪問,保護代理用於對象應該有不同的存取權限的時候。

4)            智能引用

它用於指當調用真實對象時,代理執行額外的一些操作,處理另外一些事情。例如C++中的智能指標,它取代了簡單的指標,它會對它所指向的對象執行一些額外的操作。

      

五、   代理模式的真實應用之share_ptr

看了上面的代碼,看了上面的解說,你可能覺得代理模式沒什麼作用,那麼你就錯了,下面來看看,上面四種代理模式其中一種智能引用的強大用處。

 

有使用過C++的程式員,肯定知道智能指標這個好東西,它可以讓大大減少我們對記憶體的管理難度,因為它通過以對象管理資源的方法,使指標指向向的堆記憶體像棧記憶體一樣,可以自動釋放。

 

下面就以本人實現的share_ptr來說明智能引用的代理模式的應用,首先來看看類的定義:

template <typename T>class SharePtr{    public:        SharePtr(T *tptr = NULL);        SharePtr(const SharePtr &sptr);        SharePtr& operator=(const SharePtr &sptr);        SharePtr& operator=(T *tptr);        ~SharePtr();        T&operator*()const;        T*operator->()const;        bool operator==(const SharePtr &sptr)const;        bool operator!=(const SharePtr &sptr)const;        bool operator==(const T *tptr)const;        bool operator!=(const T *tptr)const;        const T* getPtr()const;   private://function        void _decUsed();        inline void _nullTest()const;        inline bool _isSame(const SharePtr &sptr)const;        inline bool _isSame(const T *tptr)const;   private://data        T *_ptr;        size_t *_used;//引用計數,為0時釋放ptr指向的對象};

它的定義就只有這麼多了,看了上面的定義,你可以會產生疑問,這個真的應用了上面所說的代理模式嗎?上面的代理模式不是要有一個Subject類、一個RealSubject類和一個Proxy類的嗎?而RealSubject類和Proxy是Subject的子類,需要定義Subject的介面的嗎?為什麼這裡只有一個類呢?

 

現在你看不出來,我並不怪你。看下去自然會明白。

 

智能指標,這裡以share_ptr為例,它的目的就是通過一個類來模仿一個指標的行為,並提供指標沒有的功能,就是當指標變數出了範圍後,自動處理指標指向的記憶體的功能。所以上面你看到的SharePtr模板類,就相當於Proxy類。

 

那RealSubject類呢?因為智能指標是指標的代理,那麼RealSubject類當然就是SharePtr<T>中的成員變數T,我覺得說是T類型的指標T*更加恰當。哈哈,奇妙吧!

 

那麼Subject類呢?這裡是什麼充當這個類呢?從代理模式的類圖可以看到Subject類定義的是RealSubject和Proxy的共有介面,你想想看,既然RealSubject是一個指標,那麼它的操作就是*、->、==、!=和 = 這五種了,由於這些操作本來就是原生的操作,並不是什麼特別的規定,所以在這裡並沒有這個Subject,但是可以看到,這些共有的介面或者說是操作,上面的SharePtr類中,還是有實現的。

 

換一個角度來說,*、->、==、!=和 =這五類操作就是Subject類中的介面,但是在這裡並沒有必要實現一個Subject的基類,然後讓SharePtr來繼承它。因為指標並不需要繼承Subject就已經具有這五類操作了。所以這裡把這個類省去了。

 

這下你應該明白,為什麼這裡的一個類就是一個代理模式了吧。其實我覺得學習設計模式最重要的還是學習它的思想,學習的解決問題的方法以及如何用它架構我們的程式,而不是對照著類圖或者它的定義來生搬硬套。上面的智能指標就是一個例子。

 

其實智能指標並不是一個指標變數,它只是一個定義在棧上的對象,通過運算子多載使其行為像一個指標變數。當程式運行出了其範圍後,就會析構銷毀,執行相應的操作。下面再來簡單看看,這個代理為我們做了一些什麼額外的事情。

例如,當對象釋放時,會進行如下操作:

template <typename T>SharePtr<T>::~SharePtr(){    _decUsed();}template <typename T>void SharePtr<T>::_decUsed(){    --*_used;    if(*_used ==0)    {        if(_ptr!= NULL)        {            delete _ptr;            _ptr= NULL;        }        delete _used;        _used = NULL;    }}

更多的實現和額外操作,可查看原始碼。

 

六、   Android中的代理模式

在Android中代理模式也是使用廣泛的,例如ActivityManagerProxy類就是一個代理,它是ActivityManagerNative的代理,也就是說ActivityManagerProxy是上面所說的Proxy類,而ActivityManagerNative就相當於RealSubject類,它們都有一個共有的介面IActivityManager。


在這裡還有一個重要的類:ActivityManager,它相當於代理模式的類圖中的client。在這個類中,可以看到大量的getxxx函數,這些函數,都會調用到ActivityManagerNative類的getDefault()方法,而該方法會獲得一個共用的單例的IActivityManager引用,然後通過多態來調用代理中的實現。


註:由於時間的關係,沒有深入去研究。


七、   代碼地址

http://download.csdn.net/detail/ljianhui/7468509

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.