事件驱动模型的原理不再赘述,Swing是不错的实现。别人也有不错的博文来说明原理。

本文的目的是提供一种简单的,可供参考的简短代码,用来帮助理解该模型。

Project Navigator

Event

事件通用接口:

  1. package org.joshua.event.events;
  2. public interface Event {
  3. }

Click事件:

  1. package org.joshua.event.events;
  2. public class ClickEvent implements Event {
  3. }

Double click事件:

  1. package org.joshua.event.events;
  2. public class DblClickEvent implements Event {
  3. }

Listener

事件监听器通用接口:

  1. package org.joshua.event.listener;
  2. import org.joshua.event.events.Event;
  3. public interface EventListener<T extends Event> {
  4. public void handleEvent(T event);
  5. }

Click事件监听器:

  1. package org.joshua.event.listener;
  2. import org.joshua.event.events.ClickEvent;
  3. public interface ClickEventHandler extends EventListener<ClickEvent> {
  4. }

Double Click事件监听器:

  1. package org.joshua.event.listener;
  2. import org.joshua.event.events.DblClickEvent;
  3. public interface DblClickEventHandler extends EventListener<DblClickEvent> {
  4. }

Event Source

事件源通用接口:

  1. package org.joshua.event.source;
  2. import org.joshua.event.events.Event;
  3. import org.joshua.event.listener.EventListener;
  4. public interface EventSource {
  5. void addEventListener(EventListener<? extends Event> listener);
  6. void removeEventListener(EventListener<? extends Event> listener);
  7. void notifyListeners(Event event);
  8. }

模拟的按钮控件:

  1. package org.joshua.event.source;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import org.joshua.event.events.Event;
  5. import org.joshua.event.listener.EventListener;
  6. public class Button implements EventSource {
  7. protected List<EventListener<? extends Event>> listeners = new LinkedList<EventListener<? extends Event>>();
  8. @Override
  9. public void addEventListener(EventListener<? extends Event> listener) {
  10. listeners.add(listener);
  11. }
  12. @Override
  13. public void removeEventListener(EventListener<? extends Event> listener) {
  14. listeners.remove(listener);
  15. }
  16. @Override
  17. public void notifyListeners(Event event) {
  18. for (EventListener listener : listeners) {
  19. try {
  20. listener.handleEvent(event);
  21. } catch (ClassCastException e) {
  22. }
  23. }
  24. }
  25. }

Client

  1. package org.joshua.event;
  2. import org.joshua.event.events.ClickEvent;
  3. import org.joshua.event.events.DblClickEvent;
  4. import org.joshua.event.events.Event;
  5. import org.joshua.event.listener.ClickEventHandler;
  6. import org.joshua.event.listener.DblClickEventHandler;
  7. import org.joshua.event.source.Button;
  8. import org.junit.Before;
  9. import org.junit.Test;
  10. public class Client {
  11. private Event currentEvent;
  12. private Button button;
  13. @Before
  14. public void initComponent() {
  15. button = new Button();
  16. button.addEventListener(new ClickEventHandler() {
  17. @Override
  18. public void handleEvent(ClickEvent event) {
  19. System.out.println("Button was clicked!");
  20. }
  21. });
  22. button.addEventListener(new DblClickEventHandler() {
  23. @Override
  24. public void handleEvent(DblClickEvent event) {
  25. System.out.println("Button was double clicked!");
  26. }
  27. });
  28. }
  29. @Test
  30. public void testCommonEvents() {
  31. currentEvent = new ClickEvent();
  32. button.notifyListeners(currentEvent);
  33. currentEvent = new DblClickEvent();
  34. button.notifyListeners(currentEvent);
  35. }
  36. }

Button类中的notifyListener方法实现起来虽方便,利用了一把异常机制,但着实不推荐大家在项目中这样做。且不说性能问题,Listener的handleEvent方法里所有抛出的ClassCastException都需要重新包装。当然,我们可以使用annotation、限定类名等方式相对优雅地解决event和对应listener的mapping问题。

多线程事件处理机制

思路是用队列暂存事件,然后若干个事件分发器将事件分发给指定数量的事件处理线程处理。

  1. package com.joshua.test.event;
  2. import java.util.concurrent.BlockingQueue;
  3. import java.util.concurrent.ExecutorService;
  4. import java.util.concurrent.Executors;
  5. import java.util.concurrent.LinkedBlockingQueue;
  6. import com.joshua.test.event.event.Event;
  7. import com.joshua.test.event.event.EventType;
  8. import com.joshua.test.event.handler.CreateEventHandler;
  9. public class EventManager {
  10. private static final int EVENT_QUEUE_LENGTH = 1000;
  11. private static final int DISPATCHER_NUM = 2;
  12. private static final int EVENT_HANDLER_NUM = 10;
  13. public BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<Event>(EVENT_QUEUE_LENGTH);
  14. private ExecutorService eventHandlerPool;
  15. protected EventDispatcher createDispatcher() {
  16. EventDispatcher dispatcher = new EventDispatcher(this.eventQueue, this.eventHandlerPool);
  17. dispatcher.register(EventType.CREATE, CreateEventHandler.class);
  18. return dispatcher;
  19. }
  20. public void init() {
  21. eventHandlerPool = Executors.newFixedThreadPool(EVENT_HANDLER_NUM);
  22. }
  23. public void start() {
  24. for (int i = 0; i < DISPATCHER_NUM; i++) {
  25. createDispatcher().start();
  26. }
  27. }
  28. public void notify(Event event) {
  29. try {
  30. eventQueue.put(event);
  31. } catch (InterruptedException e) {
  32. }
  33. }
  34. }
  1. package com.joshua.test.event;
  2. import java.util.HashMap;
  3. import java.util.Map;
  4. import java.util.concurrent.BlockingQueue;
  5. import java.util.concurrent.ExecutorService;
  6. import com.joshua.test.event.event.Event;
  7. import com.joshua.test.event.event.EventType;
  8. import com.joshua.test.event.handler.EventHandler;
  9. @SuppressWarnings("rawtypes")
  10. public class EventDispatcher {
  11. private final BlockingQueue<Event> eventQueue;
  12. private final ExecutorService eventHandlerPool;
  13. protected final Map<EventType, Class<? extends EventHandler>> eventDispatchers = new HashMap<EventType, Class<? extends EventHandler>>();
  14. private Thread eventHandlingThread;
  15. private volatile boolean stopped = false;
  16. public EventDispatcher(BlockingQueue<Event> eventQueue, ExecutorService eventHandlerPool) {
  17. this.eventQueue = eventQueue;
  18. this.eventHandlerPool = eventHandlerPool;
  19. System.out.println("Event dispatcher starting...");
  20. }
  21. Runnable createThread() {
  22. return new Runnable() {
  23. @Override
  24. public void run() {
  25. while (!stopped && !Thread.currentThread().isInterrupted()) {
  26. Event event;
  27. try {
  28. event = eventQueue.take();
  29. } catch (InterruptedException ie) {
  30. if (!stopped) {
  31. System.out.println("Dispatcher thread interrupted");
  32. ie.printStackTrace();
  33. }
  34. return;
  35. }
  36. if (event != null) {
  37. dispatch(event);
  38. }
  39. }
  40. }
  41. };
  42. }
  43. @SuppressWarnings("unchecked")
  44. protected void dispatch(Event event) {
  45. EventType type = event.getType();
  46. try {
  47. Class<? extends EventHandler> handlerClazz = eventDispatchers
  48. .get(type);
  49. if (handlerClazz != null) {
  50. EventHandler handler = handlerClazz.newInstance();
  51. handler.setEvent(event);
  52. eventHandlerPool.submit(handler);
  53. } else {
  54. throw new Exception("No handler for registered for " + type);
  55. }
  56. } catch (Throwable t) {
  57. System.err.println("Error in dispatcher thread");
  58. t.printStackTrace();
  59. System.exit(-1);
  60. }
  61. }
  62. public void register(EventType eventType,
  63. Class<? extends EventHandler> handler) {
  64. Class<? extends EventHandler> registeredHandler = eventDispatchers
  65. .get(eventType);
  66. System.out.println("Registering " + eventType + " for "
  67. + handler);
  68. if (registeredHandler == null) {
  69. eventDispatchers.put(eventType, handler);
  70. }
  71. }
  72. public void start() {
  73. eventHandlingThread = new Thread(createThread());
  74. eventHandlingThread.setName("AsyncDispatcher event handler");
  75. eventHandlingThread.start();
  76. System.out.println("Event dispatcher started!");
  77. }
  78. public void stop() {
  79. stopped = true;
  80. if (eventHandlingThread != null) {
  81. eventHandlingThread.interrupt();
  82. try {
  83. eventHandlingThread.join();
  84. } catch (InterruptedException ie) {
  85. System.out.println("Interrupted Exception while stopping");
  86. ie.printStackTrace();
  87. }
  88. }
  89. }
  90. }

事件驱动模型的简单Java实现的更多相关文章

  1. Java学习疑惑(8)----可视化编程, 对Java中事件驱动模型的理解

    我们编写程序就是为了方便用户使用, 我觉得UI设计的核心就是简洁, 操作过于繁琐的程序让很大一部分用户敬而远之. 即使功能强大, 但是人们更愿意使用易于操作的软件. 近年流行起来的操作手势和逐渐趋于成 ...

  2. salesforce lightning零基础学习(二) lightning 知识简单介绍----lightning事件驱动模型

    看此篇博客前或者后,看一下trailhead可以加深印象以及理解的更好:https://trailhead.salesforce.com/modules/lex_dev_lc_basics 做过cla ...

  3. Java I/O模型的简单说明

    1.同步和异步 同步:如果有多个任务或者事件要发生,这些任务或者事件必须逐个地进行,一个事件或者任务的执行会导致整个流程的暂时等待,这些事件没有办法并发地执行,最简单的例子就是顺序的执行两个方法,当第 ...

  4. 事件驱动模型实例详解(Java篇)

    或许每个软件从业者都有从学习控制台应用程序到学习可视化编程的转变过程,控制台应用程序的优点在于可以方便的练习某个语言的语法和开发习惯(如.net和java),而可视化编程的学习又可以非常方便开发出各类 ...

  5. Java内存模型JMM简单分析

    参考博文:http://blog.csdn.net/suifeng3051/article/details/52611310 http://www.cnblogs.com/nexiyi/p/java_ ...

  6. (六)观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 本章我们讨论一个除前面的单例 ...

  7. 详解Spring事件驱动模型

    转载自:http://jinnianshilongnian.iteye.com/blog/1902886#comments 事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理 ...

  8. 设计模式之 观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 本章我们讨论一个除前面的单例 ...

  9. spring 事件驱动模型简介

    事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): ...

随机推荐

  1. hihocoder216周:贪心或二分

    题目链接 有N条线段,要切K刀,使得最长的线段尽量短.在最佳切割的条件下,切完之后最长的那根绳子是多长. 方法一:贪心 每次切的那一刀必然是最长的那条线段,用优先队列,每次往最长的那条线段上切一刀 方 ...

  2. java struts2入门学习--OGNL语言常用符号和常用标签学习

    一.OGNL常用符号(接上一篇文章): 1.#号 1)<s:property value="#request.username"/> 作用于struts2的域对象,而不 ...

  3. 用ElasticSearch存储日志

    介绍 如果你使用elasticsearch来存储你的日志,本文给你提供一些做法和建议. 如果你想从多台主机向elasticsearch汇集日志,你有以下多种选择: Graylog2 安装在一台中心机上 ...

  4. IP概念盛行的背后:资本在狂欢,电影想哭泣 IP,英文“Intellectual Property”的缩写,直译为“知识产权”。它的存在方式很多元,可以是一个故事,也可以是某一个形象,运营成功的IP可以在漫画、小说、电影、玩具、手游等不同的媒介形式中转换。

    IP概念盛行的背后:资本在狂欢,电影想哭泣 IP容易拉投资.谈合作,甚至还能简化宣发途径,越来越多的人涌入了电影这个产业,争抢IP成为他们进入行业的最快捷的方法.IP盛行暴露出的另一个问题是国产电影原 ...

  5. 进阶之路(中级篇) - 017 有关于Arduino 驱动舵机及相关问题

    /********************************* 代码功能:通过串口控制电机 使用函数: Serial.available(); //判断串口是否接收到数据 Serial.prin ...

  6. Mac Apache Maven 配置

    1.配置准备工作 1)配置 Maven 准备工作 下载相关软件 apache-maven-3.5.3.zip Maven 官网 Maven for Mac 配置软件下载地址,密码:q9u3. Mave ...

  7. 【Linux】分割命令split

    如果你有文件太大,导致一些携带式装置无法复制的问题,嘿嘿!找 split 就对了! 他可以帮你将一个大文件,依据文件大小或行数来分割,就可以将大文件分割成为小文件了! 快速又有效啊!真心不错- [ro ...

  8. jQuery Chosen 使用

    jQuery Chosen 使用   1.  jQuery Chosen 选择框下拉值重置: 1 2 3 4 //重置 $("#easySelBrands").val(" ...

  9. Easyui中 messager出现的位置

    $.messager.alert 弹出框的位置随页面的长度越大越靠下. $.messager.alert('消息','只能对单个客户进行清款!','info'); 弹出的位置 太靠下方.修改为: $. ...

  10. WSAAsyncSelect模型中,FD_WRITE事件什么时候触发?

    当一个套接字连接被建立上时(包括客户端的connect(),connectex()等和服务器端的accept接收到后创建的新套接字),这时会触发FD_WRITE,以后就可以用send(),WSASen ...