定義:為其他對象提供一種代理以控制對這個對象的訪問
上圖中,Subject是一個抽象類或者介面,RealSubject是實現方法類,具體的業務執行,Proxy則是RealSubject的代理,直接和client接觸的。
代理模式可以在不修改被代理對象的基礎上,通過擴展代理類,進行一些功能的附加與增強。值得注意的是,代理類和被代理類應該共同實現一個介面,或者是共同繼承某個類。
代碼:GitHub
以租房為例,我們一般用租房軟體、找中介或者找房東。這裡的中介就是代理者。
首先定義一個提供了租房方法的介面。
public interface IRentHose { void rentHose(); }
定義租房的實現類
public class RentHose implements IRentHose { @Override public void rentHose() { System.out.println("租了一間房子。。。"); } }
我要租房,房源都在中介手中,所以找中介
public class IntermediaryProxy implements IRentHose {
private IRentHose rentHose;
public IntermediaryProxy(IRentHose irentHose){ rentHose = irentHose; }
@Override public void rentHose() { System.out.println("交中介費"); rentHose.rentHose(); System.out.println("中介負責維修管理"); } }
這裡中介也實現了租房的介面。
再main方法中測試
public class Main {
public static void main(String[] args){ //定義租房 IRentHose rentHose = new RentHose(); //定義中介 IRentHose intermediary = new IntermediaryProxy(rentHose); //中介租房 intermediary.rentHose(); } }
返回信息
交中介費 租了一間房子。。。 中介負責維修管理
這就是靜態代理,因為中介這個代理類已經事先寫好了,只負責代理租房業務
如果我們直接找房東要租房,房東會說我把房子委託給中介了,你找中介去租吧。這樣我們就又要交一部分中介費了,真坑。
來看代碼如何實現,定義一個租房介面,增加一個方法。
public interface IRentHose { void rentHose(); IRentHose getProxy(); }
這時中介的方法也稍微做一下修改
@Override public void rentHose() { rentHose.rentHose(); }
@Override public IRentHose getProxy() { return this; } }
其中的getProxy()方法返回中介的代理類對象
我們再來看房東是如何實現租房:
public class LandLord implements IRentHose {
private IRentHose iRentHose = null;
@Override public void rentHose() { if (isProxy()){ System.out.println("租了一間房子。。。"); }else { System.out.println("請找中介"); } }
@Override public IRentHose getProxy() { iRentHose = new IntermediaryProxy(this); return iRentHose; }
/** * 校驗是否是代理訪問 * @return */ private boolean isProxy(){ if(this.iRentHose == null){ return false; }else{ return true; } } }
房東的getProxy方法返回的是代理類,然後判斷租房方法的調用者是否是中介,不是中介就不租房。
main方法測試:
public static void main(String[] args){
IRentHose iRentHose = new LandLord(); //租客找房東租房 iRentHose.rentHose(); //找中介租房 IRentHose rentHose = iRentHose.getProxy(); rentHose.rentHose();
}
} 請找中介 租了一間房子。。。
看,這樣就是強制你使用代理,如果不是代理就沒法訪問。
我們知道現在的中介不僅僅是有租房業務,同時還有賣房、家政、維修等得業務,只是我們就不能對每一個業務都增加一個代理,就要提供通用的代理方法,這就要通過動態代理來實現了。
中介的代理方法做了一下修改
public class IntermediaryProxy implements InvocationHandler {
private Object obj;
public IntermediaryProxy(Object object){ obj = object; }
/** * 調用被代理的方法 * @param proxy * @param method * @param args * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(this.obj, args); return result; }
在這裡實現InvocationHandler介面,此介面是JDK提供的動態代理介面,對被代理的方法提供代理。其中invoke方法是介面InvocationHandler定義必須實現的, 它完成對真實方法的調用。動態代理是根據被代理的介面生成所有的方法,也就是說給定一個介面,動態代理就會實現介面下所有的方法。通過 InvocationHandler介面, 所有方法都由該Handler來進行處理, 即所有被代理的方法都由 InvocationHandler接管實際的處理任務。
這裡增加一個賣房的業務,代碼和租房代碼類似。
IRentHose rentHose = new RentHose(); //定義一個handler InvocationHandler handler = new IntermediaryProxy(rentHose); //獲得類的class loader ClassLoader cl = rentHose.getClass().getClassLoader(); //動態產生一個代理者 IRentHose proxy = (IRentHose) Proxy.newProxyInstance(cl, new Class[]{IRentHose.class}, handler); proxy.rentHose();
ISellHose sellHose = new SellHose(); InvocationHandler handler1 = new IntermediaryProxy(sellHose); ClassLoader classLoader = sellHose.getClass().getClassLoader(); ISellHose proxy1 = (ISellHose) Proxy.newProxyInstance(classLoader, new Class[]{ISellHose.class}, handler1); proxy1.sellHose();
} 租了一間房子。。。 買了一間房子。。。
在main方法中我們用到了Proxy這個類的方法,
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
loder:類載入器,interfaces:代碼要用來代理的介面, h:一個 InvocationHandler 對象 。
InvocationHandler 是一個介面,每個代理的實例都有一個與之關聯的 InvocationHandler 實現類,如果代理的方法被調用,那麼代理便會通知和轉發給內部的 InvocationHandler 實現類,由它決定處理。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
InvocationHandler 內部只是一個 invoke() 方法,正是這個方法決定了怎麼樣處理代理傳遞過來的方法調用。
因為,Proxy 動態產生的代理會調用 InvocationHandler 實現類,所以 InvocationHandler 是實際執行者。
歡迎關註: