Android 的設計模式-----代理模式
阿新 • • 發佈:2018-12-11
代理模式
一直沒有去了解過代理模式。該文章也是我從網上找到的一些資料整理的,方便我自己日後自己查詢使用。
靜態代理
靜態代理比較簡單,是由程式設計師編寫的代理類,並在程式執行前就編譯好的,而不是由程式動態產生代理類,這就是所謂的靜態。
/**方式一:聚合式靜態代理 * @author Goser (mailto:[email protected]) * @Since 2016年9月7日 */ //1.抽象主題介面 public interface Manager { void doSomething(); } //2.真實主題類 public class Admin implements Manager { public void doSomething() { System.out.println("Admin do something."); } } //3.以聚合方式實現的代理主題 public class AdminPoly implements Manager{ private Admin admin; public AdminPoly(Admin admin) { super(); this.admin = admin; } public void doSomething() { System.out.println("Log:admin操作開始"); admin.doSomething(); System.out.println("Log:admin操作結束"); } } //4.測試程式碼 Admin admin = new Admin(); Manager m = new AdminPoly(admin); m.doSomething(); //方式二:繼承式靜態代理 //與上面的方式僅代理類和測試程式碼不同 //1.代理類 public class AdminProxy extends Admin { @Override public void doSomething() { System.out.println("Log:admin操作開始"); super.doSomething(); System.out.println("Log:admin操作開始"); } } //2.測試程式碼 AdminProxy proxy = new AdminProxy(); proxy.doSomething(); ---------------------
聚合實現方式中代理類聚合了被代理類,且代理類及被代理類都實現了同一個介面,可實現靈活多變。繼承式的實現方式則不夠靈活
動態代理
JDK動態代理步驟
- 建立一個實現InvocationHandler介面的類,它必須實現invoke()方法
- 建立被代理的類及介面
- 呼叫Proxy的靜態方法,建立一個代理類
- 通過代理呼叫方法
//1. 抽象主題 public interface Moveable { void move() throws Exception; } //2. 真實主題 public class Car implements Moveable { public void move() throws Exception { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽車行駛中…"); } } //3.事務處理器 public class TimeHandler implements InvocationHandler { private Object target; public TimeHandler(Object target) { super(); this.target = target; } /** * 引數: *proxy 被代理的物件 *method 被代理物件的方法 *args 方法的引數 * 返回: *Object 方法返回值 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛…"); method.invoke(target, args); long stopTime = System.currentTimeMillis(); System.out.println("汽車結束行駛…汽車行駛時間:" + (stopTime - startTime) + "毫秒!"); return null; } } //測試類 public class Test { public static void main(String[] args) throws Exception{ Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); /** *loader 類載入器 *interfaces 實現介面 *h InvocationHandler */ Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h); m.move(); } } ---------------------
cglib動態代理
前面分析到,因為Java只允許單繼承,而JDK生成的代理類本身就繼承了Proxy類,因此,使用JDK實現的動態代理不能完成繼承式的動態代理,但是我們可以使用cglib來實現繼承式的動態代理。
大名鼎鼎的Spring中就含有cglib動態代理,在此也以Spring中自帶的cglib完成動態代理的實現:
//1.具體主題 public class Train{ public void move(){ System.out.println("火車行駛中…"); } } //2.生成代理 public class CGLibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); public Object getProxy(Class<?> clazz){ enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } /** * 攔截所有目標類方法的呼叫 * 引數: * obj目標例項物件 *method 目標方法的反射物件 * args方法的引數 * proxy代理類的例項 */ public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { //代理類呼叫父類的方法 System.out.println("日誌開始"); proxy.invokeSuper(obj, args); System.out.println("日誌結束"); return null; } } //3.測試 public class Test { public static void main(String[] args) { CGLibProxy proxy = new CGLibProxy(); Train t = (Train) proxy.getProxy(Train.class); t.move(); } } ---------------------
結論
動態代理與靜態代理相比較,最大的好處是介面中宣告的所有方法都被轉移到呼叫處理器一個集中的方法中處理。在介面方法數量比較多的時候,我們可以進行靈活處理,而不需要像靜態代理那樣對每一個方法或方法組合進行處理。Proxy 很美很強大,但是僅支援 interface 代理。Java 的單繼承機制註定了這些動態代理類們無法實現對 class 的動態代理。好在有cglib為Proxy提供了彌補。class與interface的區別本來就模糊,在java8中更是增加了一些新特性,使得interface越來越接近class,當有一日,java突破了單繼承的限制,動態代理將會更加強大。