事件驱动模型的原理不再赘述,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. js中的getBoundingClientRect()函数

    在Chrome上,此函数返回结果包含x,y,它们的取值对应于left,top.但是x,y这种表示方式非常不直观(需要先理解x轴和y轴的方向),而left,top则清晰无歧义地表达了元素的位置.正是因此 ...

  2. select收数据

    之前写的服务器端 表示都无法收到client发的数据,找不到原因,原来是有个socket接收数据缓冲木有设置,现在设置后就可以正常收到数据啦! server端: #include <winsoc ...

  3. __cplusplus的用法(转)

    经常在/usr/include目录下看到这种字句: #ifdef __cplusplusextern "C" {#endif...#ifdef __cplusplus}#endif ...

  4. Python验证码识别处理实例 深度学习大作业

    转载自:http://python.jobbole.com/83945/ http://www.pyimagesearch.com/2014/09/22/getting-started-deep-le ...

  5. java http下载文件/上传文件保存

    private boolean downloadFile(String httpUrl, String savePath) { int byteread = 0; try { URL url = ne ...

  6. C++的iostream标准库介绍+使用详解(转)

    0 为什么需要iostream 我们从一开始就一直在利用C++的输入输出在做着各种练习,输入输出是由iostream库提供的,所以讨论此标准库是有必要的,它与C语言的 stdio库不同,它从一开始就是 ...

  7. Python学习笔记(十一)—— 函数式编程

    一.函数式编程理念 函数式编程就是一种抽象程度很高的编程范式,纯粹的函数式编程语言编写的函数没有变量,因此,任意一个函数,只要输入是确定的,输出就是确定的,这种纯函数我们称之为没有副作用.而允许使用变 ...

  8. POJ 3253 Fence Repair (哈夫曼树)

    Fence Repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19660   Accepted: 6236 Des ...

  9. 使用ant优化android项目编译速度,提高工作效率

    1.Android项目编译周期长,编译项目命令取消困难 2.在进行Android项目的编译的同时,Eclipse锁定工作区不能进行修改操作 3.在只进行资源文件的修改时,Eclipse对资源文件的修改 ...

  10. (面试)写出下面switch语句的输出结果

    (1) public static void main(String[] as) { int a = 0;  switch (a)  { case 1:   System.out.println(&q ...