快速业务通道

Java理论与实践:做个好的(事件)侦听器 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-22
中进行,这样,processFile() 方法的所 有出口都会执行它。

有时推荐的一个处理失效侦听器的方法是使用弱引用。虽然这种方法可行, 但是实现起来很麻烦。要让它工作,需要找到另外一个对象,它的生命周期恰好 是侦听器的生命周期,并安排它持有对侦听器的强引用,这可不是件容易的事。

另外一项可以用来找到隐藏失效侦听器的技术是:防止指定侦听器对象在指 定事件源上登记两次。这种情况通常是 bug 的迹象 —— 侦听器登记了,但是 没有取消登记,然后再次登记。不用检测问题,就能缓解这个问题的影响的一种 方式是:使用 Set 代替 List 来存储侦听器;或者也可以检测 List,在登记侦 听器之前检查是否已经登记了,如果已经登记,就抛出异常(或记录错误),这 样就可以搜集编码错误的证据,并采取行动。

其他侦听器问题

在编写侦听器时,应当一直注意它们将要执行的环境。不仅要注意线程安全 问题,还需要记住:侦听器也可以用其他方式为它的调用者把事情搞糟。侦听器 不该 做的一件事是:阻塞相当长一段时间(长得可以感觉得到);调用它的执 行上下文很可能希望迅速返回控制。如果侦听器要执行一个可能比较费时的操作 ,例如处理大型文本,或者要做的工作可能阻塞,例如执行 socket IO,那么侦 听器应当把这些操作安排在另一个线程中进行,这样它就可以迅速返回它的调用 者。

对于不小心的事件源,侦听器会造成麻烦的另一个方式是:抛出未检测的异 常。虽然大多数时候,我们不会故意抛出未检测异常,但是确实有些时候会发生 这种情况。如果使用清单 1 的方式调用侦听器,列表中的第二个侦听器就会抛 出未检测异常,那么不仅后续的侦听器得不到调用(可能造成应用程序处在不一 致的状态),而且有可能把执行它的线程破坏掉,从而造成局部应用程序失败。

在调用未知代码(侦听器就是这样的代码)时,谨慎的方式是在 try-catch 块中执行它,这样,行为有误的侦听器不会造成更多不必要的破坏。对于抛出未 检测异常的侦听器,您可能想自动对它取消登记,毕竟,抛出未检测异常就证明 侦听器坏掉了。(您可能还想记录这个错误或者提醒用户注意,好让用户能够知 道为什么程序停止像期望的那样继续工作。)清单 6 显示了这种方式的一个示 例,它在迭代循环内部嵌套了 try-catch 块:

清单 6. 健壮的侦听器调用List<Listener> list; for (Iterator<Listener> i=list.iterator; i.hasNext(); ) {    Listener l = i.next();    try {      l.eventHappened(event);    }    catch (RuntimeException e) {      log("Unexpected exception in listener", e);      i.remove();    } }

结束语

观察者模式对于创建松散耦合的组件、鼓励组件重用非常有用,但是它有一 些风险,侦听器的编写者和组件的编写者都应当注意。在登记侦听器时,应当一 直注意侦听器的生命周期。如果侦听器的寿命应当比应用程序的短,那么请确保 取消它的登记,这样它就可以被垃圾收集。在编写侦听器和组件时,请注意它包 含的线程安全性问题。侦听器涉及的任何对象,都应当是线程安全的,或者是受 线程约束的对象(例如 Swing 模型),侦听器应当确定自己正在正确的线程中 执行。

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号