概念
代理模式(Proxy):代理模式其實就是多一個代理類出來,替原對象進行一些操作。比如咱有的時候打官司需要請律師,因為律師在法律方面有專長,可以替咱進行操作表達咱的想法,這就是代理的意思。代理模式分為兩類:1、靜態代理(不使用jdk里面的方法);2、動態代理(使用jdk里面的InvocationHandler和Proxy)。
靜態代理由程序員創建或工具生成代理類的源碼,再編譯代理類。所謂靜態也就是在程序運行前就已經存在代理類的字節碼文件,代理類和委托類的關系在運行前就確定了。
動態代理類的源碼是在程序運行期間由JVM根據反射等機制動態的生成,所以不存在代理類的字節碼文件。代理類和委托類的關系是在程序運行時確定。
示例
這里我們舉一個靜態代理的例子:
類圖:

/** * 游戲者接口 * */ public interface IGamePlayer { // 登錄游戲 public void login(String user, String password); // 殺怪,網絡游戲的主要特色 public void killBoss(); // 升級 public void upgrade(); } /** * 游戲者 * */ public class GamePlayer implements IGamePlayer { private String name = ""; // 通過構造函數傳遞名稱 public GamePlayer(String _name) { this.name = _name; } // 打怪,最期望的就是殺老怪 public void killBoss() { System.out.println(this.name + " 在打怪!"); } // 進游戲之前你肯定要登錄吧,這是一個必要條件 public void login(String user, String password) { System.out.println("登錄名為" + user + " 的角色 " + this.name + "登錄成功!"); } // 升級,升級有很多方法,花錢買是一種,做任務也是一種 public void upgrade() { System.out.println(this.name + " 又升了一級!"); } } /** * 客戶端 對被代理對象不可見 */ public class GamePlayerProxy implements IGamePlayer { private IGamePlayer gamePlayer = null;//被代理對象 // 通過構造函數傳遞要對誰進行代練 public GamePlayerProxy(String username) { this.gamePlayer = new GamePlayer(username); } // 代練殺怪 public void killBoss() { this.gamePlayer.killBoss(); } // 代練登錄 public void login(String user, String password) { this.gamePlayer.login(user, password); } // 代練升級 public void upgrade() { this.gamePlayer.upgrade(); } } /* * 客戶端 對被代理對象不可見 */ public class GamePlayerProxy2 implements IGamePlayer { private IGamePlayer gamePlayer = null;//被代理對象 // 通過構造函數傳遞要對誰進行代練 public GamePlayerProxy2(String username) { this.gamePlayer = new GamePlayer(username); } // 代練殺怪 public void killBoss() { this.gamePlayer.killBoss(); } // 代練登錄 public void login(String user, String password) { System.out.println("登錄時間是:" + new Date().toLocaleString()); this.gamePlayer.login(user, password); } // 代練升級 public void upgrade() { this.gamePlayer.upgrade(); System.out.println("升級時間是:" + new Date().toLocaleString()); } } /* * 客戶端 對被代理對象不可見 */ public class GamePlayerProxy3 { private IGamePlayer gamePlayer; // 通過構造函數傳遞 被代練(代理)對象 public GamePlayerProxy3(IGamePlayer gamePlayer) { this.gamePlayer = gamePlayer; System.out.println("我是一名代練,我玩的角色是別人的,可以動態傳遞進來"); } public IGamePlayer getProxy() { return (IGamePlayer) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{IGamePlayer.class}, new MyInvocationHandler()); } private class MyInvocationHandler implements InvocationHandler { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("login")) { System.out.println("登錄時間是:" + new Date().toLocaleString()); } if (method.getName().equals("upgrade")) { System.out.println("升級時間是:" + new Date().toLocaleString()); } method.invoke(gamePlayer, args); return null; } } } public class Test { public static void main(String[] args) { /* * 普通的靜態代理: 客戶端不知道被代理對象,由代理對象完成其功能的調用 */ IGamePlayer proxy = new GamePlayerProxy("X"); System.out.println("開始時間是:" + new Date().toLocaleString()); proxy.login("zhangSan", "abcd"); proxy.killBoss(); proxy.upgrade(); System.out.println("結束時間是:" + new Date().toLocaleString()); System.out.println(); /* * 代理對象 增強了 被代理對象的功能 */ IGamePlayer proxy2 = new GamePlayerProxy2("M"); proxy2.login("lisi", "efg"); proxy2.killBoss(); proxy2.upgrade(); System.out.println(); /* * 動態代理:使用jdk提供的InvocationHandler,反射調用被代理對象的方法 * 結合java.reflect.Proxy 產生代理對象 * 動態傳入被代理對象構造InvocationHandler,在handler中的invoke時可以增強被代理對象的方法的功能 * 或者說:(面向切面:)在什么地方(連接點), 執行什么行為(通知) * GamePlayerProxy3中是方法名為login時通知開始時間,upgrade時通知結束時間 */ GamePlayerProxy3 dynamic = new GamePlayerProxy3(new GamePlayer("Y")); IGamePlayer dynamicPlayer = dynamic.getProxy(); dynamicPlayer.login("wangwu", "1234"); dynamicPlayer.killBoss(); dynamicPlayer.upgrade(); /* * 面向切面: 一些相似的業務邏輯需要加在眾多的地方,那們就可以把它提取到切面中, 切面也就是事務切面:如日志切面、權限切面、業務切面 */ } } 打印:
開始時間是:2014-10-8 17:19:05 登錄名為zhangSan 的角色 X登錄成功! X 在打怪! X 又升了一級! 結束時間是:2014-10-8 17:19:05 登錄時間是:2014-10-8 17:19:05 登錄名為lisi 的角色 M登錄成功! M 在打怪! M 又升了一級! 升級時間是:2014-10-8 17:19:05 我是一名代練,我玩的角色是別人的,可以動態傳遞進來 登錄時間是:2014-10-8 17:19:05 登錄名為wangwu 的角色 Y登錄成功! Y 在打怪! 升級時間是:2014-10-8 17:19:05 Y 又升了一級!
優點
(1)職責清晰
真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過后期的代理完成一件完成事務,附帶的結果就是編程簡潔清晰。
(2)代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了的作用和保護了目標對象的作用。
(3)高擴展性
新聞熱點
疑難解答