听一个可观察的实例并对它的变化做出反应很有趣。 做一些必要的事情来打断或结束这种聆听会变得很有趣。 让我们看看问题的根源和解决方法。

总览

这篇文章将首先讨论这种情况,然后再讨论常见的方法和问题所在。 然后,它将提供解决大多数问题的简单抽象。

尽管示例使用Java,但许多其他语言也存在缺陷。 提出的解决方案可以应用于所有面向对象的语言。 那些懒于自己在Java中实现抽象的人可以使用LibFX

情况

由Ky Olsen在CC-BY 2.0下发布 。

假设我们想听听属性值的变化。 这很简单:

不支持删除的简单案例

private void startListeningToNameChanges(Property<String> name) {name.addListener((obs, oldValue, newValue) -> nameChanged(newValue));
}

现在假设我们要在特定间隔内中断监听或完全停止监听。

保持参考

解决此问题的最常见方法是保留对侦听器的引用,并保留对周围属性的引用。 根据具体的用例,实现会有所不同,但是它们都可以归结为以下形式:

默认方式删除侦听器

private Property<String> listenedName;
private ChangeListener<String> nameListener;...private void startListeningToNameChanges(Property<String> name) {listenedName = name;nameListener = (obs, oldValue, newValue) -> nameChanged(newValue);listenedName.addListener(nameListener);
}private void stopListeningToNameChanges() {listenedName.removeListener(nameListener);
}

尽管这看起来不错,但我确信这实际上是一个糟糕的解决方案(尽管是默认解决方案)。

首先,额外的引用使代码混乱。 很难让他们表达出为什么要留在身边的意图,因此它们降低了可读性。

其次,它们通过向类添加新的不变式来增加复杂性:该属性必须始终是添加了侦听器的属性。 否则,对removeListener的调用将无提示地执行任何操作,并且在将来的更改时仍将执行该侦听器。 放开这可能是讨厌的。 如果类很短,则坚持不变性是容易的,但如果变得越来越复杂,则可能成为问题。

第三,引用(尤其是该属性的引用)邀请与它们进行进一步的交互。 这可能不是故意的,但没有任何办法阻止下一个开发人员继续这样做(请参阅第一点)。 而且,如果有人确实开始对该物业进行操作,第二点将成为非常现实的风险。

这些方面已经使它无法成为默认解决方案。 但是还有更多! 在许多类中必须这样做会导致代码重复。 最后,上面的实现包含一个竞争条件。

侦听器句柄

大多数问题来自直接在需要中断/结束侦听的类中处理可观察对象和侦听器。 这是不必要的,所有这些问题都可以通过一个简单的抽象来解决: ListenerHandle

ListenerHandle

public interface ListenerHandle {void attach();void detach();
}

ListenerHandle保留对可观察对象和侦听器的引用。 在调用attach()detach()它要么将侦听器添加到可观察对象,要么将其删除。 为了将此语言嵌入语言,当前将侦听器添加到可观察对象的所有方法都应返回该组合的句柄。

现在剩下要做的就是针对所有可能的情况实际实现句柄。 或者说服那些开发您喜欢的编程语言的人来做。 这留给读者练习。

注意,这解决了上面提到的所有问题,除了争用条件之外。 有两种解决方法:

  • 处理实现可能本质上是线程安全的
  • 可以实现一个同步装饰器

LibFX中的ListenerHandles

作为Java开发人员,您可以使用LibFX ,它支持三个级别的侦听器句柄。

功能了解ListenerHandles

添加侦听ListenerHandle时, LibFX的所有可实现此功能而不与Java API冲突的功能都会返回一个ListenerHandle

以WebViewHyperlinkListener为例:

将“ ListenerHandle”获取到“ WebViewHyperlinkListener”

WebView webView;ListenerHandle eventProcessingListener = WebViews.addHyperlinkListener(webView, this::processEvent);

JavaFX实用程序

由于LibFX与JavaFX有紧密的联系(可能会想到!),它提供了一个实用程序类,该类将侦听器添加到可观察对象并返回句柄。 这适用于JavaFX中存在的所有可观察/侦听器组合。

例如,让我们看一下ObservableValue<T> / ChangeListener<? superT>的组合ChangeListener<? superT> ChangeListener<? superT>

'ListenerHandles'中的一些方法

public static <T> ListenerHandle createAttached(ObservableValue<T> observableValue,ChangeListener<? super T> changeListener);public static <T> ListenerHandle createDetached(ObservableValue<T> observableValue,ChangeListener<? super T> changeListener);

ListenerHandleBuilder

在所有其他情况下,即对于上面未涵盖的任何可观察/侦听器组合,可以使用构建器来创建手柄:

为自定义类创建“ ListenerHandle”

// These classes do not need to implement any special interfaces.
// Their only connection are the methods 'doTheAdding' and 'doTheRemoving',
// which the builder does not need to know about.
MyCustomObservable customObservable;
MyCustomListener customListener;ListenerHandles.createFor(customObservable, customListener).onAttach((obs, listener) -> obs.doTheAdding(listener)).onDetach((obs, listener) -> obs.doTheRemoving(listener)).buildAttached();

反应式编程

虽然这不是关于反应式编程的文章 ,但仍应提及。 查看ReactiveX (用于许多语言,包括Java,Scala,Python,C ++,C#和更多语言)或ReactFX (或此介绍性文章 )以了解一些实现。

反射

我们已经看到,从可观察对象中删除侦听器的默认方法会产生许多危害,需要避免。 侦听器句柄抽象提供了解决许多问题的干净方法,而LibFX提供了一种实现。

翻译自: https://www.javacodegeeks.com/2015/01/dont-remove-listeners-use-listenerhandles.html

不删除侦听器–使用ListenerHandles相关推荐

  1. vue 侦听器侦听对象属性_不删除侦听器–使用ListenerHandles

    vue 侦听器侦听对象属性 听一个可观察的实例并对它的变化做出React很有趣. 做一些必要的事情来打断或结束这种聆听会变得很有趣. 让我们看看问题的根源和解决方法. 总览 这篇文章将首先讨论这种情况 ...

  2. SQL Server使用侦听器IP访问时遇到The target principal name is incorrect. Cannot generate SSPI context...

    SQL Server使用侦听器IP访问时遇到"The target principal name is incorrect. Cannot generate SSPI context&quo ...

  3. 此计算机支持多个rdp侦听程序,远程桌面侦听器证书配置

    远程桌面侦听器证书配置 09/08/2020 本文内容 本文介绍在基于 Windows Server 2012 或基于 Windows Server 2012 的服务器上配置侦听器证书的方法,该服务器 ...

  4. jpa加密_使用JPA侦听器的数据库加密

    jpa加密 最近,我不得不将数据库加密添加到一些字段中,并且发现了很多不好的建议. 建筑问题 最大的问题是建筑. 如果持久性管理器静静地处理您的加密,那么根据定义,您的体系结构将在持久性和安全性设计之 ...

  5. 使用JPA侦听器的数据库加密

    最近,我不得不将数据库加密添加到几个字段中,并且发现了很多不好的建议. 建筑问题 最大的问题是建筑. 如果持久性管理器悄悄地处理您的加密,那么根据定义,您的体系结构将在持久性和安全性设计之间要求紧密而 ...

  6. 读《Javascript高级程序设计》中的javascript事件处理程序(事件侦听器)心得

    今天读了<Javascript高级程序设计>中的javascript事件处理程序(事件侦听器)部分的内容,总结一些自己的心得: 事件就是用户或者浏览器自身执行的某种动作.例如click . ...

  7. 如果删除了DOM元素,是否还将其侦听器也从内存中删除了?

    本文翻译自:If a DOM Element is removed, are its listeners also removed from memory? 如果删除了DOM元素,它的侦听器也会从内存 ...

  8. ServletContextListener Servlet侦听器示例

    ServletContextListener is one of the many Servlet Listener we have. This is the fifth article in the ...

  9. vue的组件/data的参数/组件传值/插槽/侦听器/生命周期钩子函数

    目录 组件结构 组件的命名规则: 组件的data参数 <font color='red'> 组件的父子传值prop(通信) <font color='red'>组件的子--&g ...

最新文章

  1. typeScript面试必备之-通识七:typeScript中的可索引接口(数组,对象)+类类型接口...
  2. 单链表的python实现
  3. ios中通过ALAssetsLibrary获取所有图片
  4. python中with的用法简单来说_Python中with的用法
  5. go语言linux下开发工具,LiteIDE 开发工具指南 (Go语言开发工具)
  6. linux设备树sysfs,迅为-iMX6开发板-设备树内核-sys方式控制GPIO
  7. Pandas DataFrame loc []访问一组行和列
  8. python数字图像处理(4):图像数据类型及颜色空间转换
  9. 最全最新cpu显卡天梯图_2019.12月CPU和显卡性能天梯图
  10. 软件工程之软件工程管理
  11. 《图书管理系统》需求分析
  12. dosbox基础使用
  13. sqlserver修改主键id自增
  14. VUE查询本周、本月、本季度
  15. JAVA 实现《坦克大战联机版》游戏
  16. 6846. 【2020.11.02提高组模拟】旅人1970
  17. cpm、cpc、cps和cpa分别是什么意思
  18. 某游戏客户流失情况数据分析
  19. 灰色预测的MATLAB程序
  20. matplotlib可视化之饼图plt.pie()与plt.legend()中bbox_to_anchor参数的理解

热门文章

  1. 2016蓝桥杯省赛---java---C---10(密码脱落)
  2. 将Springboot项目放在服务器上一直运行
  3. having vs where
  4. redis主从复制部署策略+jedis设置主从
  5. ibatis(0)ibatis 与 mybatis 简述
  6. finally块不被执行的情况总结
  7. SpringMvc @RequestParam、 @RequestBody、@RequestPart 的区别
  8. json解析适配模板_认识适配器:JSON绑定概述系列
  9. 变色龙引导_Arquillian变色龙。 简化您的Arquillian测试
  10. Spring Bootstrap中具有配置元数据的高级配置