設計模式之十一代理模式
阿新 • • 發佈:2020-11-27
基本介紹
代理模式:
1)為一個物件提供一個替身,以控制對這個物件的訪問。即通過代理物件訪問目標物件,這樣做的好處是:可以在目標物件實現的基礎上,增強額外的功能操作,即擴充套件目標物件的功能。
2) 被代理的物件可以是遠端物件、建立開銷大的物件或需要安全控制的物件
3) 代理模式有不同的形式, 主要有三種 靜態代理、動態代理 (JDK代理、介面代 理)和 Cglib代理 (可以在記憶體動態的建立物件,而不需要實現介面, 他是屬於 動態代理的範疇) 。
靜態代理:
實列
具體要求
1) 定義一個介面:ITeacherDao
2) 目標物件TeacherDAO實現介面ITeacherDAO
3) 使用靜態代理方式,就需要在代理物件TeacherDAOProxy中也實現ITeacherDAO
4) 呼叫的時候通過呼叫代理物件的方法來呼叫目標物件.
5) 特別提醒:代理物件與目標物件要實現相同的介面,然後通過呼叫相同的方法來 呼叫目標物件的方法。
uml類圖
程式碼演示:
package com.hy.proxy.staticproxy; /** * @author hanyong * @date 2020/11/26 22:30 */ public interface ITeacherDao { void teach(); } package com.hy.proxy.staticproxy;/** * @author hanyong * @date 2020/11/26 22:30 */ public class TeacherDao implements ITeacherDao { @Override public void teach() { System.out.println("初始教學方式"); } } package com.hy.proxy.staticproxy; /** * @author hanyong * @date 2020/11/26 22:34 */ public class TeacherDAOProxy implementsITeacherDao { private ITeacherDao iTeacherDao; public TeacherDAOProxy(ITeacherDao iTeacherDao) { this.iTeacherDao = iTeacherDao; } @Override public void teach() { System.out.println("代理前處理"); iTeacherDao.teach(); System.out.println("代理後處理"); } } package com.hy.proxy.staticproxy; /** * @author hanyong * @date 2020/11/26 22:35 */ public class Client { public static void main(String[] args) { ITeacherDao teacherDao = new TeacherDao(); ITeacherDao teacherDaoProxy = new TeacherDAOProxy(teacherDao); teacherDaoProxy.teach(); } }
執行結果:
優缺點:
1) 優點:在不修改目標物件的功能前提下, 能通過代理物件對目標功能擴充套件
2) 缺點:因為代理物件需要與目標物件實現一樣的介面,所以會有很多代理類
3) 一旦介面增加方法,目標物件與代理物件都要維護
動態代理:
程式碼實現:
package com.hy.proxy.dynamicproxy; /** * @author hanyong * @date 2020/11/26 22:30 */ public interface ITeacherDao { void teach(); void sayHello(String name); } package com.hy.proxy.dynamicproxy; /** * @author hanyong * @date 2020/11/26 22:30 */ public class TeacherDao implements ITeacherDao { @Override public void teach() { System.out.println("初始教學方式"); } @Override public void sayHello(String name) { // TODO Auto-generated method stub System.out.println("hello " + name); } } package com.hy.proxy.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @author hanyong * @date 2020/11/27 21:31 */ public class ProxyFactory { //維護一個目標物件 , Object private Object target; //構造器 , 對target 進行初始化 public ProxyFactory(Object target) { this.target = target; } //給目標物件 生成一個代理物件 public Object getProxyInstance() { //說明 /* * public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) //1. ClassLoader loader : 指定當前目標物件使用的類載入器, 獲取載入器的方法固定 //2. Class<?>[] interfaces: 目標物件實現的介面型別,使用泛型方法確認型別 //3. InvocationHandler h : 事情處理,執行目標物件的方法時,會觸發事情處理器方法, 會把當前執行的目標物件方法作為引數傳入 */ return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub System.out.println("JDK代理開始~~"); //反射機制呼叫目標物件的方法 Object returnVal = method.invoke(target, args); System.out.println("JDK代理提交"); return returnVal; } }); } } package com.hy.proxy.dynamicproxy; /** * @author hanyong * @date 2020/11/27 21:32 */ public class Client { public static void main(String[] args) { // TODO Auto-generated method stub //建立目標物件 ITeacherDao target = new TeacherDao(); //給目標物件,建立代理物件, 可以轉成 ITeacherDao ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(target).getProxyInstance(); // proxyInstance=class com.sun.proxy.$Proxy0 記憶體中動態生成了代理物件 System.out.println("proxyInstance=" + proxyInstance.getClass()); //通過代理物件,呼叫目標物件的方法 proxyInstance.teach(); proxyInstance.sayHello(" tom "); } }
輸出結果
cglib代理
uml類圖
程式碼實現:
package com.hy.proxy.cglib; /** * @author hanyong * @date 2020/11/27 21:41 */ public class TeacherDao { public String teach() { System.out.println(" 老師授課中 , 我是cglib代理,不需要實現介面 "); return "hello"; } } package com.hy.proxy.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author hanyong * @date 2020/11/27 21:41 */ public class ProxyFactory implements MethodInterceptor { //維護一個目標物件 private Object target; //構造器,傳入一個被代理的物件 public ProxyFactory(Object target) { this.target = target; } //返回一個代理物件: 是 target 物件的代理物件 public Object getProxyInstance() { //1. 建立一個工具類 Enhancer enhancer = new Enhancer(); //2. 設定父類 enhancer.setSuperclass(target.getClass()); //3. 設定回撥函式 enhancer.setCallback(this); //4. 建立子類物件,即代理物件 return enhancer.create(); } //重寫 intercept 方法,會呼叫目標物件的方法 @Override public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable { // TODO Auto-generated method stub System.out.println("Cglib代理模式 ~~ 開始"); Object returnVal = method.invoke(target, args); System.out.println("Cglib代理模式 ~~ 提交"); return returnVal; } } package com.hy.proxy.cglib; /** * @author hanyong * @date 2020/11/27 21:42 */ public class Client { public static void main(String[] args) { // TODO Auto-generated method stub //建立目標物件 TeacherDao target = new TeacherDao(); //獲取到代理物件,並且將目標物件傳遞給代理物件 TeacherDao proxyInstance = (TeacherDao) new ProxyFactory(target).getProxyInstance(); //執行代理物件的方法,觸發intecept 方法,從而實現 對目標物件的呼叫 String res = proxyInstance.teach(); System.out.println("res=" + res); } }
執行結果: