乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      代理模式 PROXY Surrogate 結(jié)構(gòu)型 設(shè)計(jì)模式(十四)

       新進(jìn)小設(shè)計(jì) 2020-07-19
      代理模式 PROXY 別名Surrogate

      意圖

      為其他的對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問。
      代理模式含義比較清晰,就是中間人,中介公司,經(jīng)紀(jì)人...
      在計(jì)算機(jī)程序中,代理就表示一個(gè)客戶端不想或者不能夠直接引用一個(gè)對(duì)象
      而代理對(duì)象可以在客戶端和目標(biāo)對(duì)象之間起到中介的作用

      結(jié)構(gòu)

      代理模式的根本在于隔離,如下圖所示,間接訪問
      image_5c074938_56cd
      代理對(duì)象如何能夠真的代理真實(shí)對(duì)象?
      在Java語言中,看起來像的一個(gè)方式就是實(shí)現(xiàn)同一接口
      image_5c074938_5f89
       
      代理角色和真實(shí)對(duì)象角色擁有共同的抽象類型,他們擁有相同的對(duì)外接口request()方法
      ProxySubject內(nèi)部擁有一個(gè)RealSubject
      你應(yīng)該能感覺到組合模式的思想-----他們都是Subject,屬于同一個(gè)Component
      對(duì)外有一致的接口
      抽象主題角色Subject
      聲明了真實(shí)主題和代理主題的共同接口,任何使用真實(shí)主題的地方,都可以使用代理主題
      代理主題角色ProxySubject
      代理主題角色內(nèi)部含有對(duì)真實(shí)對(duì)象的引用,從而可以在任何時(shí)候操作真實(shí)主題
      代理主題提供與真實(shí)主題的相同的接口,以便任何時(shí)刻,都可以替代真實(shí)主題
      而且,代理主題還可以在真實(shí)主題執(zhí)行前后增加額外的處理,比如:經(jīng)紀(jì)人要先收下費(fèi)~
      真實(shí)主題角色RealSubject
      被代理的真實(shí)主題對(duì)象,真正工作的是他,比如經(jīng)紀(jì)人總不會(huì)站在舞臺(tái)上去~

      示例代碼

      Subject 抽象角色 定義了真正的處理請(qǐng)求 的request()方法 
      package proxy;public interface Subject {void request();
      }
      RealSubject真實(shí)主題角色,實(shí)現(xiàn)了處理請(qǐng)求的方法
      package proxy;public class RealSubject implements Subject {
      @Overridepublic void request() {
          System.out.println("realSubject process request....");
      }
      }
      Proxy代理角色
      實(shí)現(xiàn)了request()方法,用于替代真實(shí)主題,內(nèi)部調(diào)用真實(shí)主題完成請(qǐng)求
      并且額外的提供了pre和after操作
      package proxy;public class Proxy implements Subject{private Subject realSubject;
          @Overridepublic void request() {
              preRequest();
          realSubject.request();
              afterRequest();
          }     public Proxy(Subject realSubject){this.realSubject = realSubject;
          }public void preRequest(){
              System.out.println("pre request do sth....");
          }     public void afterRequest(){
              System.out.println("after request do sth....");
          }
      }
      測(cè)試類
      package proxy;public class Test {/**請(qǐng)求subject執(zhí)行請(qǐng)求
      * @param subject*/public static void askForSth(Subject subject){
          subject.request();
          System.out.println("################");
       }   
      public static void main(String[] args){
           Subject real = new RealSubject();
           Subject proxy = new Proxy(real);
           askForSth(proxy);
           askForSth(real);
          }
      }
      定義了真實(shí)對(duì)象,也定義了一個(gè)代理對(duì)象
      查看他們分別處理請(qǐng)求的結(jié)果
      image_5c074938_777b
       
      從下面的時(shí)序圖中,能更好的感受到“間接”的感覺
      在真正調(diào)用真實(shí)對(duì)象方法前,需要先執(zhí)行preRequest方法
      真實(shí)對(duì)象方法調(diào)用后,在執(zhí)行afterRequest方法
      image_5c074939_77de

      代理實(shí)現(xiàn)

      代理的實(shí)現(xiàn)分類有兩種,靜態(tài)代理和動(dòng)態(tài)代理
      前面形式描述的代理,就是靜態(tài)代理
      在編譯時(shí)期,就已經(jīng)編寫生成好了代理類的源代碼,程序運(yùn)行之前class文件就已經(jīng)生成了
      這種按照我們上面模式編寫了代理類和真實(shí)類的形式就是 靜態(tài)代理
      靜態(tài)代理經(jīng)常被用來對(duì)原有邏輯代碼進(jìn)行擴(kuò)展,原有的邏輯不需要變更,但是可以增加更多的處理邏輯
      但是,但是如果有很多的對(duì)象需要被代理怎么辦?
      如果按照靜態(tài)代理的形式,那么將會(huì)出現(xiàn)很多的代理類,勢(shì)必導(dǎo)致代碼的臃腫。
      所以后來出現(xiàn)了動(dòng)態(tài)代理

      JDK代理機(jī)制

      所謂動(dòng)態(tài)代理,按照字面意思就是動(dòng)態(tài)的進(jìn)行代理,動(dòng)態(tài)相對(duì)于靜態(tài)的含義是不需要事先主動(dòng)的創(chuàng)建代理類,可以在運(yùn)行時(shí)需要的時(shí)候,動(dòng)態(tài)的創(chuàng)建一個(gè)代理類。
      動(dòng)態(tài)代理的動(dòng)態(tài)關(guān)鍵在于代理類的動(dòng)態(tài)生成,不需要我們實(shí)現(xiàn)創(chuàng)建,從class文件的角度來看的話,是與靜態(tài)代理一樣的,仍舊有一個(gè)代理類的Class文件
      在Java中提供了內(nèi)置的動(dòng)態(tài)代理的支持。
      Java在java.lang.reflect包中提供了三個(gè)核心 Proxy,InvocationHandlerMethod  可以用于動(dòng)態(tài)代理的使用
       
      Java動(dòng)態(tài)代理簡(jiǎn)單示例
      package proxy.MyDynamicProxy;public interface Subject {void doSth();
      }
      package proxy.MyDynamicProxy;public class RealSubject implements Subject {
      @Overridepublic void doSth() {
      System.out.println("real Object do something...");
      }
      }
      package proxy.MyDynamicProxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class DynamicProxyHandler implements InvocationHandler {private Object realSubject;public DynamicProxyHandler(Object realSubject) {this.realSubject = realSubject;
      }
      @Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.println("proxy do something....");return method.invoke(realSubject, args);
      }
      }
      package proxy.MyDynamicProxy;import java.lang.reflect.Proxy;public class Test {public static void main(String[] args){
      RealSubject realSubject = new RealSubject();
      Subject proxy = (Subject) Proxy
      .newProxyInstance(Test.class.getClassLoader(), new Class[]{Subject.class}, new DynamicProxyHandler(realSubject));
      proxy.doSth();
      }
      }
      測(cè)試結(jié)果為:
      image_5c074939_41fd
       
      動(dòng)態(tài)代理到底都做了什么?
      對(duì)于靜態(tài)代理,我們有一個(gè)RealSubject,以及他的超接口Subject
      Subject定義了方法,RealSubject實(shí)現(xiàn)了方法。
      然后我們創(chuàng)建了代理類,這個(gè)代理類實(shí)現(xiàn)了Subject接口,并且將新增的邏輯添加進(jìn)來,然后通過代理類進(jìn)行方法調(diào)用。 
       
      在上面的例子中,RealSubject,以及他的超接口Subject含義不變,與靜態(tài)代理中的邏輯一樣。
      然后我們創(chuàng)建了一個(gè)調(diào)用處理器DynamicProxyHandler 實(shí)現(xiàn)了 InvocationHandler接口
      該接口只有一個(gè)方法invoke
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
      他有三個(gè)參數(shù)
      proxy - 在其上調(diào)用方法的代理實(shí)例
      method - 對(duì)應(yīng)于在代理實(shí)例上調(diào)用的接口方法的 Method 實(shí)例。Method 對(duì)象的聲明類將是在其中聲明方法的接口,該接口可以是代理類賴以繼承方法的代理接口的超接口。
      args - 包含傳入代理實(shí)例上方法調(diào)用的參數(shù)值的對(duì)象數(shù)組,如果接口方法不使用參數(shù),則為 null?;绢愋偷膮?shù)被包裝在適當(dāng)基本包裝器類(如 java.lang.Integer 或 java.lang.Boolean)的實(shí)例中。
       
      最后通過Java提供的代理機(jī)制創(chuàng)建了一個(gè)代理
          Subject proxy = (Subject) Proxy
              .newProxyInstance(Test.class.getClassLoader(), new Class[]{Subject.class}, new DynamicProxyHandler(realSubject));
      核心就是newProxyInstance方法,他創(chuàng)建了一個(gè)實(shí)現(xiàn)了Subject接口的代理類
      public static Object newProxyInstance(ClassLoader loader,
                                            Class<?>[] interfaces,
                                            InvocationHandler h)
                                     throws IllegalArgumentException
      這個(gè)方法也有三個(gè)參數(shù)
      loader - 定義代理類的類加載器
      interfaces - 代理類要實(shí)現(xiàn)的接口列表
      h - 指派方法調(diào)用的調(diào)用處理程序
       
      為什么需要這三個(gè)參數(shù)呢?
      首先,Proxy.newProxyInstance幫你動(dòng)態(tài)的創(chuàng)建方法,肯定要有一個(gè)類加載器,上面的示例中我們直接使用的測(cè)試類的類加載,這個(gè)一般是應(yīng)用程序  類加載器
      再者,動(dòng)態(tài)代理與靜態(tài)代理一樣,需要實(shí)現(xiàn)同樣的接口,那你實(shí)現(xiàn)了哪些接口呢?所以你得把接口列表告訴我
      最后,你希望有哪些處理呢?你要把處理器給我
       
      proxy.doSth();執(zhí)行時(shí),會(huì)將當(dāng)前代理實(shí)例,以及當(dāng)前方法,以及當(dāng)前方法的參數(shù)傳遞給invoke方法,所以就完成代理的功能。
       
      再來重頭理一下:
      1. 如同靜態(tài)代理,需要被代理的對(duì)象RealSubject,以及他的超接口Subject

      2. 需要實(shí)現(xiàn)InvocationHandler接口創(chuàng)建一個(gè)處理器,新增加的方法邏輯封裝在invoke方法中

      3. Proxy.newProxyInstance創(chuàng)建代理實(shí)例

      4. 使用創(chuàng)建的代理實(shí)例執(zhí)行方法

      簡(jiǎn)言之,動(dòng)態(tài)代理與靜態(tài)代理一模一樣,差別就在于不用你事先去自己主動(dòng)地創(chuàng)建一個(gè)代理類
      靜態(tài)的時(shí)候編寫了代理類,然后編譯為class然后需要時(shí)被加載到JVM,然后調(diào)用
      動(dòng)態(tài)是運(yùn)行時(shí)在需要的時(shí)候,直接生成class文件
       
      依照上面的步驟流程,你就可以借助于Java的機(jī)制實(shí)現(xiàn)動(dòng)態(tài)代理
      但是你會(huì)發(fā)現(xiàn),Proxy.newProxyInstance方法的參數(shù)需要一個(gè) Class<?>[] interfaces,這意味著什么?這意味著被代理的對(duì)象必須實(shí)現(xiàn)一個(gè)接口
      如果被代理的對(duì)象不曾實(shí)現(xiàn)任何接口怎么辦?
      給每個(gè)被代理的對(duì)象增加一個(gè)標(biāo)記接口(形式接口)?如果只是為了使用JDK的動(dòng)態(tài)代理實(shí)現(xiàn),而添加了無意義的接口這是否妥當(dāng)?

      CGLIB

      還有另外一種形式的動(dòng)態(tài)代理CGLIB
      需要兩個(gè)Jar  
      image_5c074939_55fa
      package proxy.cglib;public class RealSubject{public void doSth() {
      System.out.println("realSubject process request....");
      }
      }
      package proxy.cglib;import java.lang.reflect.Method;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;public class MyHandler implements MethodInterceptor {
      @Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)throws Throwable {
      System.out.println("before do something...");
      Object object = methodProxy.invokeSuper(o,objects);
      System.out.println("after do something...");return object;
      }
      }
      package proxy.cglib;import net.sf.cglib.proxy.Enhancer;public class Test {public static void main(String[] args){
      Enhancer enhancer = new Enhancer();
      enhancer.setSuperclass(RealSubject.class);
      enhancer.setCallback(new MyHandler());
      RealSubject subject = (RealSubject)enhancer.create();
      subject.doSth();
      }
      }
      在這個(gè)示例中,不再需要接口,僅僅只有一個(gè)真是對(duì)象RealSubject
      實(shí)現(xiàn)了一個(gè)處理器 MyHandler 繼承自 MethodInterceptor,實(shí)現(xiàn)了intercept方法
      在測(cè)試客戶端中,通過四個(gè)步驟創(chuàng)建了代理對(duì)象,然后借助于代理對(duì)象執(zhí)行
      image_5c074939_666
       
      從    enhancer.setSuperclass(RealSubject.class);這一句或許猜得到,CGLIB不依賴于接口,而是代理類繼承了真實(shí)主題類
       
      流程
      真實(shí)主題對(duì)象RealSubject是必不可少的,否則代理模式就沒有意義了
      類似JDK的代理模式,處理器也是解耦的,在CGLIB中借助于MethodInterceptor接口約定,這一步要做的事情的本質(zhì)與InvocationHandler并沒有什么太多不同---封裝附加的處理邏輯
      借助于Enhancer用來組裝處理創(chuàng)建邏輯,并且創(chuàng)建代理類
      setSuperclass設(shè)置需要繼承的類(也就是被代理的類)
      setCallback設(shè)置回調(diào)函數(shù)
      create創(chuàng)建真正的代理對(duì)象。
       
      CGLIB采用繼承的機(jī)制,如果一個(gè)類是final的怎么辦?那就歇菜了

      JDK代理機(jī)制與CGLIB對(duì)比

      目前到JDK8 據(jù)說性能已經(jīng)優(yōu)于CGLIB了
      JDK機(jī)制不需要第三方Jar,JDK默認(rèn)集成,CGLIB需要引入第三方Jar包
      JDK需要依賴真實(shí)主題對(duì)象實(shí)現(xiàn)接口,CGLIB則不需要,CGLIB繼承了真實(shí)主題
      CGLIB雖然不依賴真實(shí)主題實(shí)現(xiàn)接口,但是被代理的類不能為final,那樣的類是無法繼承的
      通常的做法是如果實(shí)現(xiàn)了接口,那么使用JDK機(jī)制,如果沒有實(shí)現(xiàn)接口,使用CGLIB

      代理用途分類

      代理模式的根本在于隔離,“間接”,只要隔離,間接,那么就可以隱藏真實(shí)對(duì)象,并且增加額外的服務(wù),優(yōu)化,管理等
      比如
      隱藏了真實(shí)的對(duì)象,比如你通過中介租房子,可能到期也沒見過房東
       
      提供了代理層,可以提供更多服務(wù)
      比如買賣房屋通過中介可以節(jié)省你合同的審校工作,很多人不懂合同中暗藏的貓膩
       
      隱藏真實(shí)對(duì)象,自然能夠起到一定的保護(hù)作用,避免了直接接觸
      比如去學(xué)校見孩子,需要先經(jīng)過老師同意
       
      通過代理,也相當(dāng)于有一個(gè)管家,可以管理外界對(duì)真實(shí)對(duì)象的接觸訪問
      比如,真實(shí)對(duì)象是電腦,管家類軟件相當(dāng)于代理,可以限制小孩子對(duì)電腦的使用時(shí)長(zhǎng)
       
      圍繞著代理帶來的特點(diǎn)“隱藏真實(shí)對(duì)象,并且增加額外的服務(wù),優(yōu)化,限制”
      在多種場(chǎng)景下,延伸出來一些分類
      遠(yuǎn)程代理 Remote
      為一個(gè)位于不同的地址空間的對(duì)象提供一個(gè)局域代表對(duì)象,這個(gè)不同的地址空間可以是本機(jī)器的,也可以是另一臺(tái)機(jī)器的
      虛擬代理 Virtual
      根據(jù)需要?jiǎng)?chuàng)建一個(gè)資源消耗較大的對(duì)象,使得此對(duì)象只在需要時(shí)才會(huì)被真正創(chuàng)建
      保護(hù)代理 Protect or Access
      控制對(duì)一個(gè)對(duì)象的訪問,如果需要,可以給不同的用戶提供不同級(jí)別的使用權(quán)限
      Cache代理
      為一個(gè)目標(biāo)操作的結(jié)果提供臨時(shí)的存儲(chǔ)空間,以便多個(gè)客戶端可以共享這些結(jié)果 
      防火墻代理 Firewall
      保護(hù)目標(biāo),防止惡意行為
      同步代理 Synchronization
      使幾個(gè)用戶能夠同時(shí)使用一個(gè)對(duì)象而沒有沖突

      智能引用 Smart Reference
      當(dāng)一個(gè)對(duì)象被引用時(shí),提供一些額外的操作,比如將對(duì)象調(diào)用次數(shù)記錄下來
       
      很顯然,這些分類其實(shí)只是代理的不同應(yīng)用場(chǎng)景,以后可能還會(huì)有更多的分類出來
      但是永遠(yuǎn)也脫離不了代理的“隔離”“間接”的根本核心。

      總結(jié)

      代理角色雖然是真實(shí)角色的“代理人”,雖然代理角色內(nèi)部依賴真實(shí)角色
      但是真實(shí)角色可以完全脫離代理人,單獨(dú)出現(xiàn)
      比如上面示例中的

              askForSth(proxy);

              askForSth(real); 

      只不過,通過代理角色會(huì)有不同的效果
       
      代理人只是會(huì)“幫助”解決他能解決的問題,它能提供的服務(wù),他做不了的事情
      比如經(jīng)紀(jì)人不會(huì)出唱片,對(duì)于出唱片的任務(wù)還是會(huì)委托給真實(shí)角色
      現(xiàn)實(shí)世界中,我們通常說真實(shí)角色委托代理角色,比如,房東找中介
      在程序世界中,通常卻說代理角色將任務(wù)委托給真實(shí)角色,委托與被委托都是相對(duì)的
      要看你到底是站在什么視角看待問題,無所謂~
       
      再次強(qiáng)調(diào),代理模式的重點(diǎn)在于增加對(duì)真實(shí)受訪對(duì)象的控制,也可以增加額外的服務(wù)。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多