一、引子 我們去科技市場為自己的機器添加點奢侈的配件,很多DIYer都喜歡去找代理商,因為在代理商那裡拿到的東西不僅質量有保證,而且價格和售後服務上都會好很多。
<!-- frame contents -->
<!-- /frame contents -->
客戶通過代理商得到了自己想要的東西,而且還享受到了代理商額外的服務;而生產廠商通過代理商將自己的產品推廣出去,而且可以將一些銷售服務的任務交給代理商來完成(當然代理商要和廠商來共同分擔風險,分配利潤),這樣自己就可以花更多的心思在產品的設計和生產上了。
在美國,任何企業的產品要想拿到市場上去賣就必須經過代理商這一個環節,否則就是非法的。看來代理商在商業運作中起著很要害的作用。 不小心把話題扯遠了,回過頭來,那麼在我們的面向對象的程序設計中,會不會有代理商這樣的角色呢?來看這篇文章的人肯定不會說:沒有!
那麼就跟著這篇文章來看看代理模式的奇妙吧。
二、定義和分類
代理模式在設計模式中的定義就是:為其他對象提供一種代理以控制對這個對象的訪問。說白了就是,在一些情況下客戶不想或者不能直接引用一個對象,而代理對象可以在客戶和目標對象之間起到中介作用,去掉客戶不能看到的內容和服務或者增添客戶需要的額外服務。
那麼什麼時候要使用代理模式呢?在對已有的方法進行使用的時候出現需要對原有方法進行改進或者修改,這時候有兩種改進選擇:修改原有方法來適應現在的使用方式,或者使用一個“第三者”方法來調用原有的方法並且對方法產生的結果進行一定的控制。第一種方法是明顯違反了“對擴展開放、對修改關閉”(開閉原則),而且在原來方法中作修改可能使得原來類的功能變得模糊和多元化(就像現在企業多元化一樣),而使用第二種方式可以將功能劃分的更加清楚,有助於後面的維護。所以在一定程度上第二種方式是一個比較好的選擇!
當然,話又說回來了,假如是一個很小的系統,功能也不是很繁雜,那麼使用代理模式可能就顯得臃腫,不如第一種方式來的快捷。這就像一個三口之家,家務活全由家庭主婦或者一個保姆來完成是比較合理的,根本不需要雇上好幾個保姆層層代理:)
根據《Java與模式》書中對代理模式的分類,代理模式分為8種,這裡將幾種常見的、重要的列舉如下:
1. 遠程(Remote)代理:為一個位於不同的地址空間的對象提供一個局域代表對象。比如:你可以將一個在世界某個角落一台機器通過代理假象成你局域網中的一部分。
2. 虛擬(Virtual)代理:根據需要將一個資源消耗很大或者比較復雜的對象延遲的真正需要時才創建。比如:假如一個很大的圖片,需要花費很長時間才能顯示出來,那麼當這個圖片包含在文檔中時,使用編輯器或浏覽器打開這個文檔,這個大圖片可能就影響了文檔的閱讀,這時需要做個圖片Proxy來代替真正的圖片。
3. 保護(Protect or Access)代理:控制對一個對象的訪問權限。比如:在論壇中,不同的身份登陸,擁有的權限是不同的,使用代理模式可以控制權限(當然,使用別的方式也可以實現)。
4. 智能引用(Smart Reference)代理:提供比對目標對象額外的服務。比如:紀錄訪問的流量(這是個再簡單不過的例子),提供一些友情提示等等。
代理模式是一種比較有用的模式,從幾個類的“小結構”到龐大系統的“大結構”都可以看到它的影子。
三、結構 代理模式中的“代理商”要想實現代理任務,就必須和被代理的“廠商”使用共同的接口(你可以想象為產品)。所以自然而然你會想到在java中使用一個抽象類或者接口(推薦)來實現這個共同的接口。於是代理模式就有三個角色組成了:
1.抽象主題角色:聲明了真實主題和代理主題的共同接口。
2.代理主題角色:內部包含對真實主題的引用,並且提供和真實主題角色相同的接口。
3.真實主題角色:定義真實的對象。
使用類圖來表示下三者間的關系如下:
當然,圖上所示的是代理模式中的一個具體情況。而代理模式可以非常靈活的使用其他方式來實現,這樣就與圖上所示有很大的區別。
也許,現在你已經對代理模式已經有了一個宏觀的熟悉了,下面我們來看看怎麼實際的使用代理模式。
四、舉例 以論壇中已注冊用戶和游客的權限不同來作為第一個例子:已注冊的用戶擁有發帖,修改自己的注冊信息,修改自己的帖子等功能;而游客只能看到別人發的帖子,沒有其他權限。為了簡化代碼,更好的顯示出代理模式的骨架,我們這裡只實現發帖權限的控制。 首先我們先實現一個抽象主題角色MyForum,裡面定義了真實主題和代理主題的共同接口——發帖功能。