JAVA 設(shè)計模式之代理模式——閉包代理(初創(chuàng)篇)

1. 場景還原

其實最開始, 我是在用 java swing 做一個 endpoint-io-transfer 的應(yīng)用工具(一個用于從citrix下載文件的工具).

頁面里面有幾個按鈕, 點擊按鈕執(zhí)行邏輯功能, 相關(guān)代碼大概是這樣:

private JComponent getToolBar() {
   // ..... 無關(guān)代碼省略 .....
   JButton singleScanButton = new JButton("單次掃描");
   singleScanButton.addActionListener(e -> {
      // ..... 省略按鈕邏輯代碼, 執(zhí)行可能耗費500ms以上 .....
   });
   // ..... 無關(guān)代碼省略 .....
}

java swing 的按鈕執(zhí)行是同步的, 如果執(zhí)行邏輯耗費時間較長會導(dǎo)致gui不響應(yīng), 而且如果短時間多次點擊的話會導(dǎo)致執(zhí)行多次, 于是就想著處理一下.

處理方式很簡單, 就是用鎖和多線程搞一下就行了, 但是會把代碼搞得很難看.

按鈕有10個左右, 雖然可以使用公共類或靜態(tài)方法的形式簡化, 但是這次我卻盯上了中間的那個 lambda 表達(dá)式.

我想著 能不能對這個lambda表達(dá)式進(jìn)行處理, 處理后的lambda表達(dá)式直接能夠滿足我的需求呢?

于是就搗鼓了下去.

2. 處理點擊事件

一會兒, 我就寫好了這樣的類

/**
* 將傳入的 Consumer<T> then 作為 被代理函數(shù)式接口實例 傳入, 將該對象的 onceExe 方法作為 代理方法實例 返回
* 
* 邏輯: 完成 函數(shù)式接口實例 的 異步單線程 代理
*/
public static class OnceExecutorForConsumer<T> {

   private final Lock lock = new ReentrantLock();

   /**
   * 被代理的方法
   */
   private final Consumer<T> then;

   private Consumer<T> skip;

   public OnceExecutorForConsumer(Consumer<T> then) {
      this.then = then;
   }

   /**
   * 代理方法
   * 
   * <p>
   *     每次調(diào)用新建一個線程對參數(shù)進(jìn)行處理, 主線程不阻塞, 分線程競爭鎖, 搶到運行 then, 搶不到運行 skip
   * </p>
   */
   public void onceExe(final T e) {
      new Thread(() -> {
            if (lock.tryLock()) {
               try {
                  if (then != null) {
                        then.accept(e);
                  }
               } finally {
                  lock.unlock();
               }
            } else {
               if (skip != null) {
                  skip.accept(e);
               }
            }
      }).start();
   }

   public OnceExecutorForConsumer<T> setSkip(Consumer<T> skip) {
      this.skip = skip;
      return this;
   }
}

原來的按鈕部分代碼就成了下面的調(diào)用方式

   private JComponent getToolBar() {
      // ..... 無關(guān)代碼省略 .....
      JButton singleScanButton = new JButton("單次掃描");
      singleScanButton.addActionListener(new OnceExecutorForConsumer<>((ActionEvent e) -> {
         // ..... 省略按鈕邏輯代碼, 執(zhí)行可能耗費500ms以上 .....
      }).setSkip(e -> log.debug("多次點擊無效"))::onceExe);
      // ..... 無關(guān)代碼省略 .....
   }

如此完美完成了既定目標(biāo)

3. 分析 OnceExecutorForConsumer

實際上, 在寫 OnceExecutorForConsumer 的時候, 我就已經(jīng)發(fā)現(xiàn)了, OnceExecutorForConsumer 會是一個很強的代理類.

和靜態(tài)代理不同, 這種代理方式代理的是函數(shù)式接口, 將一個函數(shù)式接口作為被代理對象傳入, 傳出一個代理的函數(shù)式接口, 然后這個函數(shù)式接口就可以實現(xiàn)對原有函數(shù)式接口對象的代理.

  1. 眾所周知, 靜態(tài)代理的弊端之一是代理類和被代理類需要實現(xiàn)同一個接口, 代理類, 被代理類 和接口之間耦合度很高, 同一個功能, 接口和被代理類發(fā)生變化, 那么代理類也要跟著變化, 代理類簡直成適配器了.

    然而, 如果對函數(shù)式接口對象進(jìn)行代理的話會怎么樣呢?

    1. 相同結(jié)構(gòu)的函數(shù)式接口可以相互轉(zhuǎn)化.
    2. 函數(shù)式接口結(jié)構(gòu)很少, 也就只有 參數(shù)和返回值的區(qū)別而已.
    3. 不通的函數(shù)式接口實例也可以通過簡單的方式適配連接在一起.

    可見, 函數(shù)式接口實例的代理不會有 代理類和代理對象的接口問題, 導(dǎo)致代理類泛濫的問題, 這就使得這種代理模式相當(dāng)靈活.

  2. 在 java 中, 萬物皆對象, 對象中的方法也看作是一個對象, 這個對象可以轉(zhuǎn)換為函數(shù)式接口實例.

    也就是說, 這種代理功能極其強大, 它能夠直接和間接代理所有方法. 一類在手, 簡直天下我有啊有木有.

  3. 這種代理方式主打成為針對方法的工具類, 相對于普通的方法操控方法來說, 它有一個閉包的優(yōu)勢, 閉包背后有一個完整的類, 這可以賦予他強大的功能.

起名:閉包代理

我們看下這種代理方式, 它是構(gòu)造類的過程中將函數(shù)方法變成它的一個成員變量, 之后返回創(chuàng)建的類的另一個方法作為代理方法, 之后整個對象僅僅往外暴漏了一個方法, 也就是說因為這個方法被外界引用, 導(dǎo)致這個對象能夠存活下去.

大家想到了什么, 這就是Js中的閉包邏輯啊!

雖然java中也有閉包, 但那個閉包我直接忽略了!

那么到這里, 實際上稱呼也就定了, 閉包加代理, 那就閉包代理啊!

其實本來我想起名為函數(shù)代理函數(shù)式接口代理來著, 但是吧, 前一個感覺像數(shù)學(xué), 后一個名字太長.

從此, java里面除了靜態(tài)代理 & 動態(tài)代理之外, 至少在我的字典里面就可以新增一種代理方式了: 閉包代理


這篇文章關(guān)于閉包代理僅僅寫了個開頭,
如果你對后續(xù)內(nèi)容感興趣,
請看下一篇 JAVA 設(shè)計模式之代理模式——閉包代理(集成篇)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 夜鶯2517閱讀 128,087評論 1 9
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭,有人歡樂有人憂愁,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,814評論 28 54
  • 兔子雖然是枚小碩 但學(xué)校的碩士四人寢不夠 就被分到了博士樓里 兩人一間 在學(xué)校的最西邊 靠山 兔子的室友身體不好 ...
    待業(yè)的兔子閱讀 2,759評論 2 9
  • 信任包括信任自己和信任他人 很多時候,很多事情,失敗、遺憾、錯過,源于不自信,不信任他人 覺得自己做不成,別人做不...
    吳氵晃閱讀 6,355評論 4 8

友情鏈接更多精彩內(nèi)容