代理模式又稱為委托模式。代理模式從字面上很好理解,有些事情你可以不必親自去做,而是通過更為專業的人或者機構去做。比如你開公司需要工商注冊。你可以選擇自己去了解相關的規章制度,親自跑腿去辦理。也可以通過專業機構辦理。這樣你就不需要去了解辦理的細節,隻需把材料交給機構。機構會為你完成注冊工作。在這個過程中,機構不但會為你完成機構注冊,而且還有可能為你辦理一些你并不知道的增值服務。這就是典型的代理模式。
1. 實現代理模式我們再看一個生活中的例子。房屋買賣中經常會出現代理的情況。當賣家不在房屋所在地時,可能會委托自己的親人或者朋友進行交易。而買方會和代理人直接進行交易。交易中間的問題代理人會回答,手續代理人會辦理。如下圖:
這個代理人不太老實,私自加了20萬,想賺差價。所以不要以為代理人真的隻是代理,在這個過程中他可以加入自己的邏輯處理。而客戶和被代理人并不知道。
我們看看采用代理模式如何實現這個場景。
首先真正賣掉房子的還是房主,隻不過和買房人直接進行買賣的是代理人。那麼房主和代理人有一個公共的行為都是賣房。那麼我們可以抽象出一個接口定義賣房的行為。房主和代理人都需要實現這個接口。真正的賣房邏輯在房主的實現中,代理人的賣房實現隻是調用房主的實現而已。要達到這個目的,代理人需要持有房主的引用。而買方進行買賣的時候,僅和代理人打交道。不用知道房主是誰,也不用讓房主到現場過戶。甚至連房主身在何處都不知道。
上面其實就是這個例子的程序設計。代碼如下:
房屋交易接口代碼:
public interface RealEstate {
void sell();
}
房主代碼:
public class Seller implements RealEstate {
@Override
public void sell() {
System.out.println("賣了房子");
}
}
代理人代碼:
public class SellerProxy implements RealEstate{
private Seller seller;
@Override
public void sell() {
if(seller==null){
seller = new Seller();
}
seller.sell();
System.out.println("退稅辦理完畢");
}
}
類圖:
代理人在這裡有什麼用處呢?沒有代理人,直接和房主買就好了啊?試想下,假如現在有了新的買房政策,交易完成後可以退稅,那麼在不修改房主代碼的前提下,我們隻需要修改此代理人的代碼即可。如果在其他地方賣房沒有此政策,隻需要定義另外一個地區的代理人即可,這裡實現了開閉原則。其實代理模式還有很多好處和适用的場景。我們下面詳細來看。
2. 代理模式優缺點2.1 優點代理模式在客戶端代碼和真正的邏輯代碼中引入了一層代理,這樣做有很多好處:代理模式
- 隐藏邏輯的真正實現對象。上面的例子中,如果賣房人身份特殊,那麼通過代理人來賣房,可以不讓買房人接觸到自己;
- 隐藏委托類的某些行為,在代理類認為應該觸發時再觸發;
- 代理類可以為委托類的行為附加一些邏輯處理,例如上例中的退稅。
- 代理類和委托類實現同一個接口,因此隻能面向接口代理;
- 代理類和委托類實現同一個接口。即使代理類隻想代理某個行為,也需要實現接口所有方法;
- 代理類和委托類需要一一對應。如果你有段邏輯需要對所有的方法都附加上,靜态代理是無法實現的。
針對代理模式的三個優點,我們來看看有哪些适用場景。
- 遠程調用代理:在分布式系統中,我們經常會調用其他系統的服務。通過代理模式,可以對客戶端代碼隐藏遠程調用的細節;
- 虛代理:有一個典型的場景,加載一個包含大量大 size 圖片的頁面時,為了更好的用戶體驗,可以通過圖片代理類先把圖片的位置占好,保證排版的正确。當滾動到某個圖片位置的時候才去加載圖片;
- 保護代理:當委托對象需要訪問權限控制時,可以通過代理類來控制權限進行保護;
- 智能指引:為委托對象增加一層控制。比如記錄訪問次數,當為 0 的時候,可以釋放掉。第一次引用一個對對象時,把它裝入内存。訪問委托對象前,檢查是否已經有其他訪問已經鎖定了它,以确保其他對象不能改變它。
代理模式由 Suject 接口,RealSubject 實現和 Proxy 類構成。Proxy 類同樣要實現 Suject 接口。同時 Proxy 類依賴 RealSubject 類。代理模式對方的調用增加了間接性。利用間接性,可以加入額外的邏輯。這也是我們常說的 AOP,即面向切面編程。
,