不删除侦听器–使用ListenerHandles
听一个可观察的实例并对它的变化做出反应很有趣。 做一些必要的事情来打断或结束这种聆听会变得很有趣。 让我们看看问题的根源和解决方法。
总览
这篇文章将首先讨论这种情况,然后再讨论常见的方法和问题所在。 然后,它将提供解决大多数问题的简单抽象。
尽管示例使用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相关推荐
- vue 侦听器侦听对象属性_不删除侦听器–使用ListenerHandles
vue 侦听器侦听对象属性 听一个可观察的实例并对它的变化做出React很有趣. 做一些必要的事情来打断或结束这种聆听会变得很有趣. 让我们看看问题的根源和解决方法. 总览 这篇文章将首先讨论这种情况 ...
- 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 ...
- 此计算机支持多个rdp侦听程序,远程桌面侦听器证书配置
远程桌面侦听器证书配置 09/08/2020 本文内容 本文介绍在基于 Windows Server 2012 或基于 Windows Server 2012 的服务器上配置侦听器证书的方法,该服务器 ...
- jpa加密_使用JPA侦听器的数据库加密
jpa加密 最近,我不得不将数据库加密添加到一些字段中,并且发现了很多不好的建议. 建筑问题 最大的问题是建筑. 如果持久性管理器静静地处理您的加密,那么根据定义,您的体系结构将在持久性和安全性设计之 ...
- 使用JPA侦听器的数据库加密
最近,我不得不将数据库加密添加到几个字段中,并且发现了很多不好的建议. 建筑问题 最大的问题是建筑. 如果持久性管理器悄悄地处理您的加密,那么根据定义,您的体系结构将在持久性和安全性设计之间要求紧密而 ...
- 读《Javascript高级程序设计》中的javascript事件处理程序(事件侦听器)心得
今天读了<Javascript高级程序设计>中的javascript事件处理程序(事件侦听器)部分的内容,总结一些自己的心得: 事件就是用户或者浏览器自身执行的某种动作.例如click . ...
- 如果删除了DOM元素,是否还将其侦听器也从内存中删除了?
本文翻译自:If a DOM Element is removed, are its listeners also removed from memory? 如果删除了DOM元素,它的侦听器也会从内存 ...
- ServletContextListener Servlet侦听器示例
ServletContextListener is one of the many Servlet Listener we have. This is the fifth article in the ...
- vue的组件/data的参数/组件传值/插槽/侦听器/生命周期钩子函数
目录 组件结构 组件的命名规则: 组件的data参数 <font color='red'> 组件的父子传值prop(通信) <font color='red'>组件的子--&g ...
最新文章
- typeScript面试必备之-通识七:typeScript中的可索引接口(数组,对象)+类类型接口...
- 单链表的python实现
- ios中通过ALAssetsLibrary获取所有图片
- python中with的用法简单来说_Python中with的用法
- go语言linux下开发工具,LiteIDE 开发工具指南 (Go语言开发工具)
- linux设备树sysfs,迅为-iMX6开发板-设备树内核-sys方式控制GPIO
- Pandas DataFrame loc []访问一组行和列
- python数字图像处理(4):图像数据类型及颜色空间转换
- 最全最新cpu显卡天梯图_2019.12月CPU和显卡性能天梯图
- 软件工程之软件工程管理
- 《图书管理系统》需求分析
- dosbox基础使用
- sqlserver修改主键id自增
- VUE查询本周、本月、本季度
- JAVA 实现《坦克大战联机版》游戏
- 6846. 【2020.11.02提高组模拟】旅人1970
- cpm、cpc、cps和cpa分别是什么意思
- 某游戏客户流失情况数据分析
- 灰色预测的MATLAB程序
- matplotlib可视化之饼图plt.pie()与plt.legend()中bbox_to_anchor参数的理解
热门文章
- 2016蓝桥杯省赛---java---C---10(密码脱落)
- 将Springboot项目放在服务器上一直运行
- having vs where
- redis主从复制部署策略+jedis设置主从
- ibatis(0)ibatis 与 mybatis 简述
- finally块不被执行的情况总结
- SpringMvc @RequestParam、 @RequestBody、@RequestPart 的区别
- json解析适配模板_认识适配器:JSON绑定概述系列
- 变色龙引导_Arquillian变色龙。 简化您的Arquillian测试
- Spring Bootstrap中具有配置元数据的高级配置