2019獨角獸企業重金招聘Python工程師標準>>>
代理模式
- 給某一個對象提供一個代理,并由代理對象控制對原對象的引用。
靜態代理
靜態代理是由我們編寫好的類,在程序運行之前就已經編譯好的的類,此時就叫靜態代理。 說理論還是比較懵逼的,直接上代碼:
抽象主題,可以想象成我們的業務接口。
/*** 抽象主題。* @author wushuaiping* @date 2018/3/13 下午10:13*/
public interface ISubject {/*** 比如現在有個業務功能,需要開啟某項校驗。*/void enableCheck();
}
真實主題,可以想象成我們對業務接口的實現類。
/*** 真實主題* @author wushuaiping* @date 2018/3/13 下午10:21*/
public class RealSubject implements ISubject {public void enableCheck() {System.out.println("我開啟了某項校驗~~");}
}
但是有一天,我突然想加個日志記錄,但是我不想去改動原有的方法。那么我們就可以使用這種方式:
/*** 代理類* @author wushuaiping* @date 2018/3/13 下午10:23*/
public class ProxySubject implements ISubject{private ISubject subject;public ProxySubject(ISubject subject){super();this.subject = subject;}// 對被代理對象的方法進行增強public void enableCheck() {before();subject.enableCheck();after();}private void before(){System.out.println("我記錄一下啟動校驗前的相關日志。");}private void after(){System.out.println("我記錄一下啟動校驗后的相關日志。");}
}
我們使用靜態代理后,來試試看這種方式能不能行?測試代碼:
public class Main{public static void main(String[] args) throws ApiException {ProxySubject proxy = new ProxySubject(new RealSubject());proxy.enableCheck();}
}
運行結果:
我記錄一下啟動校驗前的相關日志
我開啟了某項校驗~~
我記錄一下啟動校驗后的相關日志。
靜態代理模式相對比較簡單,但是缺點肯定也是有的:
-
一個代理對象只能服務于一個類。如果有很多類需要記錄日志的話,你的一個一個去實現。。累不死你。。
-
代理對象必須實現接口,如上。一個字:還是累。
動態代理
這里動態代理使用的是JDK的動態代理實現的,JDK的動態代理必須是目標對象實現接口才可以。也就是相當于我們上面的業務實現類(RealSubject)。使用CGLIB就不用實現接口也可完成動態代理,但是今天時間不多了,明天還得搬磚,所以先把JDK動態代理學了,明天再學學CGLIB的動態代理。 代碼如下:
要實現動態代理;需要先去實現InvocationHandler接口,這個接口提供了invoke方法,該方法相信用過反射或者AOP的同學應該都比較熟悉,我這里就不多講了。實現了這個后我們可以調用目標方法了,但是我們需要代理的對象還不知道從何而來,所以我們還需要使用JDK提供的Proxy.newProxyInstance方法,第一個參數是目標代理類的類加載器,第二個參數是目標代理類實現的接口,第三個參數的話是目標代理類的調用處理程序就是InvokeHandler啦。用該方法可以生產代理對象。
/*** 使用Java的動態代理實現* @author wushuaiping* @date 2018/3/13 下午10:43*/
public class DynamicProxy implements InvocationHandler {private Object target;public Object getProxyInstance(Object target){this.target = target;// 使用Java的獲取代理實例方法來獲取代理實例。。好繞啊。。反正就是獲取代理實例-_-return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), this);}// 增強, 調用目標方法public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before();// 因為我們需要被增強的方法enableCheck是沒有返回參數的,所以不需要返回值。// 如果有返回值 Object res = method.invoke(proxy, args); return res;就可以了method.invoke(target, args);after();return null;}private void before(){System.out.println("操作之前的日志記錄~~");}private void after(){System.out.println("操作之后的日志記錄~~");}
}
Test case
public static void main(String[] args) throws ApiException {DynamicProxy proxy = new DynamicProxy();ISubject subject = (ISubject)proxy.getProxyInstance(new RealSubject());subject.enableCheck();}
運行結果:
操作之前的日志記錄~~
我開啟了某項校驗~~
操作之后的日志記錄~~
今天的設計模式算是學完啦,抽象工廠模式感覺我可能思維不夠抽象,所以到現在還沒能理解抽象工廠模式到底能干嘛?實際中有何用處?本文用于個人學習記錄,有寫的不好的地方,還請各位大佬指點一二!
good night!