事件驱动模型的原理不再赘述,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. ubuntu安装过程中遇到问题小结

    一.下载 官网下载地址:https://www.ubuntu.com/download/desktop/contribute?version=16.04.4&architecture=amd6 ...

  2. 【解决问题】failed: java.lang.RuntimeException: org.openqa.selenium.WebDriverException: Unexpected error launching Internet Explorer.

    failed: java.lang.RuntimeException: org.openqa.selenium.WebDriverException: Unexpected error launchi ...

  3. Apache启用GZIP压缩网页传输

    首先我们先了解Apache Gzip的相关资料. 一.gzip介绍 Gzip是一种流行的文件压缩算法,现在的应用十分广泛,尤其是在Linux平台.当应用Gzip压缩到一个纯文本文件时,效果是非常明显的 ...

  4. 深入学习 Git 工作流

    原文  https://github.com/xirong/my-git/blob/master/git-workflow-tutorial.md   个人在学习git工作流的过程中,从原有的 SVN ...

  5. Linux提示“libc.so.6: version `GLIBC_2.14' not found”系统的glibc版本太低

    http://www.linuxidc.com/Linux/2017-01/139806.htm http://www.linuxidc.com/Linux/2015-04/116472.htm

  6. JVM调优总结(一)-- 堆和栈的基本概念

    数据类型 Java虚拟机中,数据类型可以分为两类:基本类型和引用类型.基本类型的变量保存原始值,即:他代表的值就是数值本身:而引用类型的变量保存引用值.“引用值”代表了某个对象的引用,而不是对象本身, ...

  7. shell脚本监控cpu/内存使用率 转

    该脚本检测cpu和内存的使用情况,只需要调整memorySetting.cpuSetting.userEmail要发邮件报警的email地址即可 如果没有配置发邮件参数的哥们,已配置了的,直接飞到代码 ...

  8. Oracle 12C -- shutdown CDB

    SQL> select name,open_mode from v$pdbs; NAME OPEN_MODE ------------------------------ ---------- ...

  9. Python 爬虫编码格式问题 gb2312转换utf8

    遇到的问题是:爬取网页得到的结果如下(部分)  里面的中文出现乱码. <!DOCTYPE html> <html lang='zh-CN'> <head> < ...

  10. 纯干货,Spring-data-jpa详解(转)

    本篇进行Spring-data-jpa的介绍,几乎涵盖该框架的所有方面,在日常的开发当中,基本上能满足所有需求.这里不讲解JPA和Spring-data-jpa单独使用,所有的内容都是在和Spring ...