经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
监听器模式、观察者模式
来源:cnblogs  作者:土豆蛋炒饭  时间:2018/11/6 10:22:06  对本文有异议

最近在学习netty的时候,发现里面用到了监听器模式,感觉非常实用,以前看设计模式的时候只是看,并没有用上。其实这是一个非常重要并实用的设计模式,在很多框架里面都用到了。

netty里面的应用:

  1. serverBootstrap.bind(8000).addListener(new GenericFutureListener<Future<? super Void>>() {
  2. public void operationComplete(Future<? super Void> future) {
  3. if (future.isSuccess()) {
  4. System.out.println("端口绑定成功!");
  5. } else {
  6. System.err.println("端口绑定失败!");
  7. }
  8. }
  9. });

回调函数

为什么先提到回调函数呢?因为回调函数是理解监听器、观察者模式的关键。刚毕业的时候老大也经常和我说Java中的回调。

wiki中的定义

回调函数,或简称回调(Callback 即call then back 被主函数调用运算后会返回主函数),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。

通俗的定义:就是程序员A写了一段程序(程序a),其中预留有回调函数接口,并封装好了该程序。程序员B要让a调用自己的程序b中的一个方法,于是,他通过a中的接口回调自己b中的方法。

demo:这里有两个实体,回调抽象者接口、回调者(程序a)

  • 回调接口(ICallBack)
  1. public interface ICallBack {
  2. public void callBack();
  3. }
  • 回调者(用于调用回调函数的类)
  1. public class Caller {
  2. public void call(ICallBack callBack) {
  3. System.out.println("start...");
  4. callBack.callBack();
  5. System.out.println("end...");
  6. }
  7. }
  • 回调测试
  1. public class CallDemo {
  2. public static void main(String[] args) {
  3. Caller caller = new Caller();
  4. caller.call(() -> System.out.println("回调成功"));
  5. }
  6. }
  • 控制台输出
  1. start...
  2. 回调成功
  3. end...

这个模型和执行一个线程Thread很像。没错,Thread就是回调者,Runnable就是一个回调接口。

事件监听器

事件监听器就是自己监听的事件一旦被触发或改变,立即得到通知,做出响应。

Java的事件监听机制可概括为3点:

  1. Java的事件监听机制涉及到事件源事件监听器事件对象三个组件,监听器一般是接口,用来约定调用方式
  2. 当事件源对象上发生操作时,它将调用事件监听器的一个方法,并将事件对象传递过去
  3. 事件监听器实现类,通常是由开发人员编写,开发人员通过事件对象拿到事件源,从而对事件源上的操作进行处理

这里为了方便,直接用了 jdk,EventListener 监听器

  • 监听器接口
  1. public interface EventListener extends java.util.EventListener {
  2. /**
  3. * 事件处理
  4. */
  5. void handleEvent(EventObject eventObject);
  6. }
  • 事件对象
  1. public class EventObject extends java.util.EventObject {
  2. public EventObject(Object source) {
  3. super(source);
  4. }
  5. public void doEvent() {
  6. System.out.println("通知一个事件源 source:" + this.getSource());
  7. }
  8. }
  • 事件源
  1. public class EventSource {
  2. // 监听器列表,监听器的注册 加入此列表
  3. private List<EventListener> listeners = new ArrayList<>();
  4. public void addListener(EventListener eventListener) {
  5. listeners.add(eventListener);
  6. }
  7. public void removeListener(EventListener eventListener) {
  8. listeners.remove(eventListener);
  9. }
  10. public void notifyListenerEvent(EventObject eventObject) {
  11. for (EventListener eventListener : listeners) {
  12. eventListener.handleEvent(eventObject);
  13. }
  14. }
  15. }
  • 测试执行
  1. public class EventDemo {
  2. public static void main(String[] args) {
  3. EventSource eventSource = new EventSource(); // 事件源
  4. eventSource.addListener(new EventListener() { // 事件源 调用监听器的一个方法,并传递事件对象
  5. @Override
  6. public void handleEvent(EventObject eventObject) {
  7. eventObject.doEvent();
  8. if (eventObject.getSource().equals("closeWindow")) {
  9. System.out.println("doClose"); // 回调
  10. }
  11. }
  12. });
  13. EventObject eventObject = new EventObject("closeWindow"); // 事件对象
  14. eventSource.notifyListenerEvent(eventObject); // 触发事件
  15. }
  16. }
  • 控制台输出
  1. 通知一个事件源 source:closeWindow
  2. doClose

到这里我们了解了什么是监听器模式了。EventListener是一个回调接口类,handleEvent是一个回调函数接口,通过回调模型,EventSource事件源便可回调具体监听器动作。

观察者模式

观察者模式的原理其实和监听器一样,使用的关键在于搞清楚什么是观察者、什么是被观察者

  1. 观察者相当于事件监听
  2. 被观察者相当于事件源和事件

为了方便,同样直接使用jdk自带的Observer

  • 观察者
  1. public class Watcher implements Observer {
  2. @Override
  3. public void update(Observable o, Object arg) {
  4. if (arg.toString().equals("openWindow")) {
  5. System.out.println("打开窗口");
  6. }
  7. }
  8. }
  • 被观察者
  1. public class Watched extends Observable {
  2. public void notifyObservers(Object arg) {
  3. /**
  4. * 为了避免并发冲突,设置了 changed 标志位 changed=true,则当前线程可以通知所有观察者,内部同步块会设置为false;
  5. * 通知过程中,正在新注册的和撤销的无法通知到
  6. */
  7. super.setChanged();
  8. /**
  9. * 事件触发,通知所有感兴趣的观察者
  10. */
  11. super.notifyObservers(arg);
  12. }
  13. }
  • 测试执行
  1. public class WatcherDemo {
  2. public static void main(String[] args) {
  3. Watched watched = new Watched();
  4. Watcher watcher = new Watcher();
  5. watched.addObserver(watcher);
  6. watched.addObserver(new Observer() {
  7. @Override
  8. public void update(Observable o, Object arg) {
  9. if (arg.toString().equals("closeWindow")) {
  10. System.out.println("关闭窗口");
  11. }
  12. }
  13. });
  14. watched.notifyObservers("openWindow");
  15. watched.notifyObservers("closeWindow");
  16. }
  17. }
  • 控制台输出
  1. 打开窗口
  2. 关闭窗口

总结

从实现和调用过程来看,观察者和监听器模式基本一样。基本上都是这个逻辑当事件源对象上发生操作时,它将调用事件监听器的一个方法,并将事件对象传递过去,套用到观察者模式上面就是,当被观察者发生操作时,观察者将根据被观察者所做出的操作 进行对应的操作。

应用

  1. netty中监听连接
  2. guava 中的 ListenableFuture,采用监听器模型解决了原生JDK中 future.get() 一直阻塞结果的问题。

参考文章:https://my.oschina.net/u/923324/blog/792857

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号