【java項目實戰】代理模式(Proxy Pattern),靜態代理 VS 動態代理

來源:互聯網
上載者:User

標籤: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 動態代理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.