JAVA 设计模式之代理模式——闭包代理(初创篇)

1. 场景还原

其实最开始, 我是在用 java swing 做一个 endpoint-io-transfer 的应用工具(一个用于从citrix下载文件的工具).

页面里面有几个按钮, 点击按钮执行逻辑功能, 相关代码大概是这样:

private JComponent getToolBar() {
   // ..... 无关代码省略 .....
   JButton singleScanButton = new JButton("单次扫描");
   singleScanButton.addActionListener(e -> {
      // ..... 省略按钮逻辑代码, 执行可能耗费500ms以上 .....
   });
   // ..... 无关代码省略 .....
}

java swing 的按钮执行是同步的, 如果执行逻辑耗费时间较长会导致gui不响应, 而且如果短时间多次点击的话会导致执行多次, 于是就想着处理一下.

处理方式很简单, 就是用锁和多线程搞一下就行了, 但是会把代码搞得很难看.

按钮有10个左右, 虽然可以使用公共类或静态方法的形式简化, 但是这次我却盯上了中间的那个 lambda 表达式.

我想着 能不能对这个lambda表达式进行处理, 处理后的lambda表达式直接能够满足我的需求呢?

于是就捣鼓了下去.

2. 处理点击事件

一会儿, 我就写好了这样的类

/**
* 将传入的 Consumer<T> then 作为 被代理函数式接口实例 传入, 将该对象的 onceExe 方法作为 代理方法实例 返回
* 
* 逻辑: 完成 函数式接口实例 的 异步单线程 代理
*/
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>
   *     每次调用新建一个线程对参数进行处理, 主线程不阻塞, 分线程竞争锁, 抢到运行 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;
   }
}

原来的按钮部分代码就成了下面的调用方式

   private JComponent getToolBar() {
      // ..... 无关代码省略 .....
      JButton singleScanButton = new JButton("单次扫描");
      singleScanButton.addActionListener(new OnceExecutorForConsumer<>((ActionEvent e) -> {
         // ..... 省略按钮逻辑代码, 执行可能耗费500ms以上 .....
      }).setSkip(e -> log.debug("多次点击无效"))::onceExe);
      // ..... 无关代码省略 .....
   }

如此完美完成了既定目标

3. 分析 OnceExecutorForConsumer

实际上, 在写 OnceExecutorForConsumer 的时候, 我就已经发现了, OnceExecutorForConsumer 会是一个很强的代理类.

和静态代理不同, 这种代理方式代理的是函数式接口, 将一个函数式接口作为被代理对象传入, 传出一个代理的函数式接口, 然后这个函数式接口就可以实现对原有函数式接口对象的代理.

  1. 众所周知, 静态代理的弊端之一是代理类和被代理类需要实现同一个接口, 代理类, 被代理类 和接口之间耦合度很高, 同一个功能, 接口和被代理类发生变化, 那么代理类也要跟着变化, 代理类简直成适配器了.

    然而, 如果对函数式接口对象进行代理的话会怎么样呢?

    1. 相同结构的函数式接口可以相互转化.
    2. 函数式接口结构很少, 也就只有 参数和返回值的区别而已.
    3. 不通的函数式接口实例也可以通过简单的方式适配连接在一起.

    可见, 函数式接口实例的代理不会有 代理类和代理对象的接口问题, 导致代理类泛滥的问题, 这就使得这种代理模式相当灵活.

  2. 在 java 中, 万物皆对象, 对象中的方法也看作是一个对象, 这个对象可以转换为函数式接口实例.

    也就是说, 这种代理功能极其强大, 它能够直接和间接代理所有方法. 一类在手, 简直天下我有啊有木有.

  3. 这种代理方式主打成为针对方法的工具类, 相对于普通的方法操控方法来说, 它有一个闭包的优势, 闭包背后有一个完整的类, 这可以赋予他强大的功能.

起名:闭包代理

我们看下这种代理方式, 它是构造类的过程中将函数方法变成它的一个成员变量, 之后返回创建的类的另一个方法作为代理方法, 之后整个对象仅仅往外暴漏了一个方法, 也就是说因为这个方法被外界引用, 导致这个对象能够存活下去.

大家想到了什么, 这就是Js中的闭包逻辑啊!

虽然java中也有闭包, 但那个闭包我直接忽略了!

那么到这里, 实际上称呼也就定了, 闭包加代理, 那就闭包代理啊!

其实本来我想起名为函数代理函数式接口代理来着, 但是吧, 前一个感觉像数学, 后一个名字太长.

从此, java里面除了静态代理 & 动态代理之外, 至少在我的字典里面就可以新增一种代理方式了: 闭包代理


这篇文章关于闭包代理仅仅写了个开头,
如果你对后续内容感兴趣,
请看下一篇 JAVA 设计模式之代理模式——闭包代理(集成篇)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容

  • 夜莺2517阅读 127,720评论 1 9
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,536评论 28 53
  • 兔子虽然是枚小硕 但学校的硕士四人寝不够 就被分到了博士楼里 两人一间 在学校的最西边 靠山 兔子的室友身体不好 ...
    待业的兔子阅读 2,603评论 2 9
  • 信任包括信任自己和信任他人 很多时候,很多事情,失败、遗憾、错过,源于不自信,不信任他人 觉得自己做不成,别人做不...
    吴氵晃阅读 6,190评论 4 8