概念
プロキシ モード (プロキシ): プロキシ モードは、実際には、元のオブジェクトに対していくつかの操作を実行する追加のプロキシ クラスです。たとえば、法廷に行くときに弁護士を雇う必要がある場合があります。弁護士は法律の専門知識を持っており、私たちに代わって私たちの考えを表明できるからです。これが代理店の意味です。プロキシ モードは 2 つのカテゴリに分類されます: 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; } } }
Print:
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(); /* * 面向切面: 一些相似的业务逻辑需要加在众多的地方,那们就可以把它提取到切面中, 切面也就是事务切面:如日志切面、权限切面、业务切面 */ } }
利点
(1) 明確な責任
本当の役割は、実際のビジネスロジックを実装することです。この責任の事務は後続のエージェントを通じて完了され、それに伴う結果はシンプルで明確なプログラミングになります。
(2) プロキシ オブジェクトは、クライアントとターゲット オブジェクトの間の仲介的な役割を果たすことができ、重要な役割を果たし、ターゲット オブジェクトを保護します。
(3) 高いスケーラビリティ
デザイン パターンでプロキシ パターンを使用してプロジェクトを構築する Java のその他の例については、PHP 中国語 Web サイトの関連記事に注目してください。