標籤:rman reflect return fonts this 理解 post private 應該
這篇博文,我們主要以類圖和代碼的形式來對照學習一下靜態代理和動態代理。重點解析各自的優缺點。
定義
代理模式(Proxy Pattern)是對象的結構型模式,代理模式給某一個對象提供了一個代理對象,並由代理對象控制對原對象的引用。
代理模式不會改變原來的介面和行為,僅僅是轉由代理幹某件事,代理能夠控制原來的目標,比如:代理商,代理商僅僅會買東西,但並不會改變行為。不會製造東西。
讓我們通過以下的代碼好好理解一下這句話。
分類
靜態代理和動態代理
靜態代理
靜態代理類圖
代碼示範範例
介面
package com.liang.pattern;public interface UserManager {public void addUser(String userId,String userName);public void delUser(String userId);public void modifyUser(String userId,String userName);public String findUser(String userId);}
目標對象
package com.liang.pattern;public class UserManagerImpl implements UserManager {public void addUser(String userId, String userName) {try{System.out.println("UserManagerImpl.addUser() userId-->>" + userId);}catch(Exception e){e.printStackTrace();throw new RuntimeException();}}public void delUser(String userId) {System.out.println("UserManagerImpl.delUser() userId-->>" + userId);}public String findUser(String userId) {System.out.println("UserManagerImpl.findUser() userId-->>" + userId);return "於亮";}public void modifyUser(String userId, String userName) {System.out.println("UserManagerImpl.modifyUser() userId-->>" + userId);}}
代理類,我們使用代理對象做一些日誌記錄,我們將簡略的列印資訊到控制台。
package com.liang.pattern;public class UserManagerImplProxy implements UserManager {private UserManager userManager;public UserManagerImplProxy(UserManager userManager){this.userManager = userManager;}public void addUser(String userId, String userName) { //記錄日誌等操作或列印輸入參數System.out.println("start-->>addUser() userId-->>" + userId);try{userManager.addUser(userId, userName); //運行成功。列印成功資訊System.out.println("success-->>addUser()");}catch(Exception e){e.printStackTrace(); //失敗時。列印失敗資訊System.out.println("error-->>addUser()");//throw new RuntimeException();}}public void delUser(String userId) {//同上,略userManager.delUser(userId);}public String findUser(String userId) {//同上。略userManager.findUser(userId);return null;}public void modifyUser(String userId, String userName) {//同上。略userManager.modifyUser(userId, userName);}}
client調用
package com.liang.pattern;public class Client {/** * @param args */public static void main(String[] args) {UserManager userManager = new UserManagerImplProxy(new UserManagerImpl());userManager.addUser("001","於亮");}}
輸出結果,此方法運行成功
start-->>addUser() userId-->>001UserManagerImpl.addUser() userId-->>001success-->>addUser()
從類圖我們能夠看出。client本來能夠直接和目標對象打交道,代理中間加了一個間接層。他們實現的功能是一樣的,也沒有改變參數。相信大家對上面的類圖和代碼非常熟悉。跟我們平時看別人的博文一樣。沒有不論什麼差別。以下我們看一下靜態代理的優缺點。
優缺點
長處:
1、直觀感受,靜態代理是實實在在的存在的,我們自己寫的。
2、在編譯期增加,提前就指定好了誰調用誰,效率高。
缺點:
相同,它的長處也成了它致命的缺點。
1、靜態代理非常麻煩。須要大量的代理類
當我們有多個目標對象須要代理時,我就須要建立多個代理類。改變原有的代碼,改的多了就非常有可能出問題,必須要又一次測試。
2、反覆的代碼會出如今各個角落裡,違背了一個原則:反覆不是好味道
我們應該杜絕一次次的反覆。
3、在編譯期增加,系統的靈活性差
我們能夠看到代理類的每一個方法中,都有記錄日誌,運行成功或失敗的代碼,每一個方法都反覆了一遍,假設我們須要改動的話,並沒有比不用靜態代理時降低改動的地方。僅僅是不用改動目標類。動態代理非常好的為我們攻克了這個問題。以下我們看一下動態代理。
動態代理
動態代理類圖
代碼示範範例
代理類(不明確,就看看凝視吧)
package com.liang.pattern;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 採用JDK動態代理必須實現InvocationHandler介面。採用Proxy類建立對應的代理類 * @author liang * */public class ProxyHandler implements InvocationHandler {private Object targetObject;/** * 目標的初始化方法。依據目標組建代理程式類 * @param targetObject * @return */public Object newProxyInstance(Object targetObject){this.targetObject = targetObject;//第一個參數,目標的裝載器//第二個參數,目標介面,為每一個介面組建代理程式//第三個參數,調用實現了InvocationHandler的對象。當你一調用代理,代理就會調用InvocationHandler的invoke方法return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);}/** * 反射,這樣你能夠在不知道詳細的類的情況下,依據配置的參數去調用一個類的方法。在靈活編程的時候很實用。 */public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {//記錄日誌等操作或列印輸入參數System.out.println("start-->>" + method.getName());for(int i=0;i<args.length;i++){//列印調用目標方法的參數System.out.println(args[i]);}Object ret = null;try{//調用目標方法ret = method.invoke(targetObject, args);//運行成功。列印成功資訊System.out.println("success-->>" + method.getName());}catch(Exception e){e.printStackTrace();//失敗時,列印失敗資訊System.out.println("error-->>" + method.getName());throw e;}return ret;}}
client調用
package com.liang.pattern;public class Client {/** * @param args */public static void main(String[] args) {ProxyHandler proxyHandler = new ProxyHandler();UserManager userManager = (UserManager)proxyHandler.newProxyInstance(new UserManagerImpl());String name = userManager.findUser("0001");System.out.println("client.main-->>" + name);}}
輸出結果,執行成功
start-->>findUser0001UserManagerImpl.findUser() userId-->>0001success-->>findUserclient.main-->>於亮
介面和目標類,同上,我就不再浪費大家的頻寬了。
優缺點
長處:
1、一個動態代理類更加簡單了,能夠解決建立多個靜態代理的麻煩,避免不斷的反覆多餘的代碼
2、調用目標代碼時,會在方法“執行時”動態增加,決定你是什麼類型,才調誰,靈活
缺點:
1、系統靈活了。可是相比而言,效率減少了,比靜態代理慢一點
2、動態代理比靜態代理在代碼的可讀性上差了一點,不太easy理解
3、JDK動態代理僅僅能對實現了介面的類進行代理
總結
靜態代理VS動態代理,打成了平手,各自有各的獨特之處,均不可取代,在項目中究竟使用哪種代理,沒有最好。僅僅有更合適。
【java項目實戰】代理模式(Proxy Pattern),靜態代理 VS 動態代理