溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

動(dòng)態(tài)代理的理解

發(fā)布時(shí)間:2020-08-11 14:49:49 來源:網(wǎng)絡(luò) 閱讀:102 作者:ckllf 欄目:編程語言

  1.代理模式概述

  為什么要有“代理”? 生活中就有很多例子,例如委托業(yè)務(wù)等等,代理就是被代理者沒有能力或者不愿意去完成某件事情,需要找個(gè)人代替自己去完成這件事,這才是“代理”存在的原因。例如,我現(xiàn)在需要出國,但是我不愿意自己去辦簽證、預(yù)定機(jī)票和酒店(覺得麻煩 ,那么就可以找旅行社去幫我辦,這時(shí)候旅行社就是代理,而我自己就是被代理了。

  代理模式的定義:ProxyPattern(即:代理模式),23種常用的面向?qū)ο筌浖脑O(shè)計(jì)模式之一為其他對象提供一種代理以控制對這個(gè)對象的訪問。在某些情況下,一個(gè)對象不適合或者不能直接引用另一個(gè)對象,而代理對象可以在客戶端和目標(biāo)對象之間起到中介的作用。

  2.靜態(tài)代理

  以下我們借用JinLian和XiMen的例子來介紹一下靜態(tài)代理

  2.1不使用代理模式時(shí)

  JinLian類的內(nèi)部有一個(gè)happy方法,此時(shí)如果我們的XiMen類如果想要使用這個(gè)方法,正常情況下直接創(chuàng)建一個(gè)JinLian類調(diào)用happy方法即可

  public class JinLian{

  public void happy() {

  System.out.println("金蓮happy...");

  }

  }

  public class XiMen {

  public static void main(String[] args) {

  JinLian jinLian =new JinLian();

  jinLian.happy();

  }

  }

  2.2使用靜態(tài)代理

  如果我們使用靜態(tài)代理模式的話,XiMen類如果想要調(diào)用happy方法,那么它便不會(huì)直接去找JinLian類,而是通過一個(gè)代理對象WangPo間接找到JinLian類。這樣做的好處是,我們可以通過WangPo這個(gè)代理,在happy方法中添加一些想要的功能,例如:

  public class WangPo {

  JinLian jinLian ;

  public WangPo(JinLian jinLian) {

  this.jinLian = jinLian;

  }

  public void happy(){

  openHouse();

  jinLian.happy();

  clear();

  }

  public void clear(){

  System.out.println("打掃戰(zhàn)場...");

  }

  public void openHouse(){

  System.out.println("以做衣服的名義把2人約到房間...");

  }

  }//WangPo

  public class XiMen {

  public static void main(String[] args) {

  JinLian jinLian =new JinLian();

  WangPo wangPo =new WangPo(jinLian);

  wangPo.happy();

  }

  }//XiMen

  public class JinLian {

  public void happy() {

  System.out.println("金蓮happy...");

  }

  }//JinLian

  這樣,XiMen類想要調(diào)用happy方法,并且想要使用新增的功能時(shí),只需要調(diào)用WangPo的happy方法即可。

  2.3靜態(tài)代理改進(jìn)

  現(xiàn)在,雖然實(shí)現(xiàn)了代理模式,但是目前的代理對象和委托對象都已經(jīng)固定了,這樣做局限性很大,我們的XiMen類如果想要調(diào)用其它委托者的Happy方法,就只能找其它的代理對象,此時(shí)我們對代碼再次改進(jìn)一下,新加一個(gè)FindHappy接口,委托者對象只需要實(shí)現(xiàn)FinHappy接口,便可以實(shí)現(xiàn)一個(gè)代理對象代理多個(gè)委托對象。如果,XiMen現(xiàn)在想要通過WangPo使用JinLian和YanPoXi的happy方法。我們可以做出如下改寫

  public interface FindHappy {// 抽象角色

  void happy();

  }

  public class JinLian implements FindHappy {//委托者1

  @Override

  public void happy() {

  System.out.println("金蓮happy...");

  }

  }//JinLian

  public class YanPoXi implements FindHappy {//委托者2

  @Override

  public void happy() {

  System.out.println("閻婆惜happy...");

  }

  }//YanPoXi

  public class WangPo implements FindHappy {//代理者

  FindHappy findHappy;

  public WangPo(FindHappy findHappy) {

  this.findHappy = findHappy;

  }

  public void openHouse(){

  System.out.println("以做衣服的名義把2人約到房間...");

  }

  @Override

  public void happy() {

  openHouse();

  // 讓委托者h(yuǎn)appy()

  findHappy.happy();

  clear();

  }

  public void clear(){

  System.out.println("打掃戰(zhàn)場...");

  }

  }

  public class XiMen {

  public static void main(String[] args) {

  JinLian jinLian = new JinLian();

  YanPoXi yanPoXi = new YanPoXi();

  WangPo wangPo = new WangPo(yanPoXi);

  WangPo wangPo1 =new WangPo(jinLian);

  wangPo.happy();

  wangPo1.happy();

  }

  }

  如此一來我們便可以通過一個(gè)代理對象代理所有重寫了happy方法的對象

  這便是靜態(tài)代理模式

  3.動(dòng)態(tài)代理

  動(dòng)態(tài)代理與靜態(tài)代理的區(qū)別是,動(dòng)態(tài)代理的代理對象是在使用者調(diào)用委托者的方法時(shí)才創(chuàng)建的,動(dòng)態(tài)代理它可以直接給某一個(gè)目標(biāo)(被代理 對象)對象(實(shí)現(xiàn)了某個(gè)或者某些接口)生成一個(gè)代理對象,也就是當(dāng)XiMen類想要使用happy方法時(shí),代理對象才會(huì)生成,并且不需要代理類存在

  3.1動(dòng)態(tài)代理原理

  動(dòng)態(tài)代理與代理模式原理是一樣的,只是它沒有具體的代理類,直接通過反射生成了一個(gè)代理對象。簡而言之:動(dòng)態(tài)代理就是直接通過反射生成一個(gè)代理對象,代理類是不需要存在的鄭州好的婦科醫(yī)院 http://www.zzkedayy.com/

  3.2動(dòng)態(tài)代理的獲取及使用

  jdk提供一個(gè)Proxy類可以直接給實(shí)現(xiàn)接口類的對象直接生成代理對象

  Proxy的API介紹

  Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)生成一個(gè)代理對象,這個(gè)方法的返回值類型是一個(gè)Object類型,但是在此方法的第三個(gè)參數(shù)的匿名內(nèi)部類中我們重寫了委托者的方法,而委托者又必定實(shí)現(xiàn)了FindHappy接口,因此此處我們可以使用向下強(qiáng)轉(zhuǎn),并用一個(gè)Findhappy接口的對象進(jìn)行接收

  參數(shù)1:ClassLoader loader 被代理對象的類加載器, 一般使用被代理對象的類加載器

  參數(shù)2:Class[] interfaces 被代理對象的要實(shí)現(xiàn)的接口 一般使用的被代理對象實(shí)現(xiàn)的接口

  參數(shù)3:InvocationHandler h (接口)(使用匿名內(nèi)部類直接實(shí)現(xiàn))執(zhí)行處理類返回值: 代理對象

  InvocationHandler中的invoke(Object proxy, Method method, Object[] args)方法:調(diào)用代理類的任何方法,此方法都會(huì)執(zhí)行,因此當(dāng)一個(gè)委托對象中有多個(gè)方法需要代理時(shí),需要在此匿名內(nèi)部類中使用反射獲取方法名,判斷是哪個(gè)方法在請求代理,一一實(shí)現(xiàn)各個(gè)方法需要增添的功能

  3.1:代理對象(慎用)參數(shù)

  3.2:當(dāng)前執(zhí)行的方法參數(shù)

  3.3:當(dāng)前執(zhí)行的方法運(yùn)行時(shí)傳遞過來的參數(shù)返回值:當(dāng)前方法執(zhí)行的返回值

  public class Demo1 {

  public static void main(String[] args) {

  // 動(dòng)態(tài)產(chǎn)生一個(gè)JinLian類的代理對象 類似生成王婆代理對象

  FindHappy proxy = (FindHappy) Proxy.newProxyInstance(JinLian.class.getClassLoader(), JinLian.class.getInterfaces(), new InvocationHandler() {

  public void openHouse(){

  System.out.println("以做衣服的名義把2人約到房間...");

  }

  @Override

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

  // 但凡是代理對象調(diào)用方法,這個(gè)invoke方法就會(huì)執(zhí)行

  // 參數(shù)1proxy:代理對象(慎用),因?yàn)榇韺ο笳{(diào)用方法就會(huì)執(zhí)行invoke,很容易出現(xiàn)遞歸,出現(xiàn)棧內(nèi)存溢出

  // 參數(shù)2 method:當(dāng)前代理對象調(diào)用的方法

  // 參數(shù)3:當(dāng)前代理對象調(diào)用的方法,運(yùn)行時(shí)傳遞過來的參數(shù)

  // 返回值:當(dāng)前方法執(zhí)行的返回值

  if(method.getName()=="happy"){

  openHouse();

  method.invoke(JinLian.class.newInstance());// 類似 jinLian.happy()

  clear();

  return null;

  }

  }

  public void clear(){

  System.out.println("打掃戰(zhàn)場...");

  }

  });

  // 使用代理對象調(diào)用方法

  proxy.happy();

  }


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI