代理模式(一) ---- 靜態(tài)代理

最近看了馬士兵老師的設(shè)計(jì)模式視頻,感覺其中最難也最感興趣的就是代理模式了。馬士兵老師從靜態(tài)代理的兩種基本方式出發(fā),到初步實(shí)現(xiàn)指定接口的動(dòng)態(tài)代理,最后到模仿 JDK 的動(dòng)態(tài)代理,講的都很詳細(xì)。現(xiàn)在我來給大家梳理一下整個(gè)思路,希望對(duì)大家有所幫助。


  1. 想要看懂動(dòng)態(tài)代理所需要具備的知識(shí):

    • 需要對(duì) java 語法有基本的了解
    • 需要初步具備對(duì)面向?qū)ο缶幊趟枷氲脑O(shè)計(jì)思想
    • 了解多態(tài)的概念。
  2. 什么是代理模式?
    代理模式 (Proxy Pattern) :給某一個(gè)對(duì)象提供一個(gè)代 理,并由代理對(duì)象控制對(duì)原對(duì)象的引用。代理模式的英 文叫 做Proxy 或 Surrogate,它是一種對(duì)象結(jié)構(gòu)型模式。

    這里給出一個(gè)例子:假設(shè)現(xiàn)在有 Tank 這個(gè)類,其繼承了 Moveable 接口,里面有一個(gè) move() 方法,現(xiàn)在需要統(tǒng)計(jì)這個(gè)方法的運(yùn)行時(shí)間,要求不能改變這個(gè)類的源代碼,問有幾種實(shí)現(xiàn)方式?

    moveable 接口 :

    package proxy;
    
    public interface Moveable  {
        void move() ;
    }
    

    Tank 類:

    package proxy;
    
    public class Tank implements Moveable {
        @Override
        public void move() throws InterruptedException {
        System.out.println("Tank moving ...");
        Thread.sleep(10000);
        }
    }
    

    答: 聚合 and 繼承

    • 繼承:新建一個(gè)類 Tank1 繼承 Tank,重寫其 move() 方法:
    package proxy;
    
    public class Tank1 extends Tank {
        @Override
        public void move() throws InterruptedException {
            long startTime = System.currentTimeMillis() ;
            super.move();
            long endTime = System.currentTimeMillis() ;
            System.out.println("time : " + (endTime - startTime));
        }
    }
    
    • 聚合:新建一個(gè)類 Tank2,也實(shí)現(xiàn) Moveable 接口,定義一個(gè) Moveable 的實(shí)例變量,調(diào)用其 move() 方法,并添加代碼
    package proxy;
    
    public class Tank2 implements Moveable{
        public Tank2(Moveable m) {
            this.m = m;
        }
    
        private Moveable m;
    
        @Override
        public void move() throws InterruptedException {
            long startTime = System.currentTimeMillis() ;
            m.move();
            long endTime = System.currentTimeMillis() ;
            System.out.println("time : " + (endTime - startTime));
        }
    }
    
    

    以上的代碼就是初步的代理模式。即在不改變被代理對(duì)象的前提下,對(duì)其里面的方法或字段進(jìn)行加工處理。

  3. 那么問題來了,兩種代理模式哪種比較好?
    現(xiàn)在再給出一個(gè)需求,我們需要在統(tǒng)計(jì) Tank 對(duì)象方法運(yùn)行時(shí)間的基礎(chǔ)上,再加一個(gè)記錄方法運(yùn)行的日志代理,而后再改變兩個(gè)代理的前后順序。

    • 繼承實(shí)現(xiàn):

      • 添加一個(gè)記錄日志代理:再新建一個(gè) Tank3 類,繼承 Tank1 類,再重寫其 move() 方法
      • 改變兩個(gè)代理的前后順序:再新建一個(gè) Tank4 類,繼承 Tank 類,先重寫 move() 方法添加日志代理,再新建一個(gè) Tank5 類,繼承 Tank3 類,再重寫 move() 方法添加時(shí)間代理。以此類推。
    • 聚合實(shí)現(xiàn):

      • 再添加一個(gè)日志代理:新建一個(gè) Tank3 類,實(shí)現(xiàn) Moveable 接口,定義一個(gè) Moveable 類型變量,把代理過的 Tank1 對(duì)象傳進(jìn)來,調(diào)用其 move() 方法。
      public class Tank6 implements Moveable {
          public Tank6(Moveable m) {
              this.m = m;
          }
      
          private Moveable m ;
      
          @Override
          public void move() throws InterruptedException {
              System.out.println("Log start...");
              m.move();
              System.out.println("Log end ...");
          }
      }
      

      這里給一下客戶端 Client 的代碼及運(yùn)行結(jié)果:


      運(yùn)行結(jié)果
      • 改變兩個(gè)代理的順序:先把被代理的 tank 對(duì)象傳給 Tank6 實(shí)現(xiàn)日志代理,得到 tankLogProxy 對(duì)象,再將其傳給 Tank2 實(shí)現(xiàn)時(shí)間代理。

      這里給一下客戶端 Client 的代碼及運(yùn)行結(jié)果:


      運(yùn)行結(jié)果

    到了這里,相信各位已經(jīng)能看出來了。代理模式的實(shí)現(xiàn),還是聚合的方法比較好,特別是在改變代理順序的需求下,只需要改變客戶端的代理順序即可,可以避免類的無限擴(kuò)增。


代理模式中很重要的一點(diǎn)是多態(tài)的應(yīng)用,我們可以看出來,在 Tank2 和 Tank6 中,我們都是實(shí)現(xiàn)的 Moveable 接口,即我們要實(shí)現(xiàn)代理的必須是同一類對(duì)象,這里也正是我們到目前為止所說的不足之處,即只能實(shí)現(xiàn)靜態(tài)代理,在下一篇,我們實(shí)現(xiàn)初步的動(dòng)態(tài)代理。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,764評(píng)論 18 399
  • 上一篇文章我們講了靜態(tài)代理的實(shí)現(xiàn)方式,并比較了聚合實(shí)現(xiàn)靜態(tài)代理和繼承實(shí)現(xiàn)效果的不同。今天我們來逐步實(shí)現(xiàn)動(dòng)態(tài)代理,并...
    偷星辰夜閱讀 928評(píng)論 0 0
  • 多態(tài) 任何域的訪問操作都將有編譯器解析,如果某個(gè)方法是靜態(tài)的,它的行為就不具有多態(tài)性 java默認(rèn)對(duì)象的銷毀順序與...
    yueyue_projects閱讀 976評(píng)論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,908評(píng)論 18 139
  • Q1: 我是2017年畢業(yè)的內(nèi)科專業(yè)型研究生,現(xiàn)有內(nèi)科規(guī)培證,但我的工作換成了康復(fù)專業(yè),所以我想請(qǐng)問: 1.以后我...
    紅成閱讀 11,654評(píng)論 2 0