事件驱动模型的原理不再赘述,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. MATLAB 求两个矩阵的 欧氏距离

    欧式距离定义: 欧式距离公式有如下几种表示方法: MATLAB 求两个矩阵的 欧氏距离 : 如果定义两个矩阵分别为a,b则定义c=(a-b).^2所求距离d=sqrt(sum(c(:)))

  2. 【转】Kafka 之 中级

    摘要: Kafka配置介绍,原理介绍及生产者,消费者Java基本使用方法. 1.    配置 Ø  Broker主要配置 参数 默认值 说明(解释) broker.id =0   每一个broker在 ...

  3. SaltStack入门到精通第一篇:安装SaltStack

    SaltStack入门到精通第一篇:安装SaltStack 作者:纳米龙  发布日期:2014-06-09 17:50:36   实际环境的设定: 系统环境: centos6 或centos5 实验机 ...

  4. 自由是有代价的:聊聊这几年尝试的道路 要想生活好,别看哲学书和思想书。简单看看可以,看多了问题就大了。还是要去研究研究些具体的问题。别jb坐在屋子里,嘴里念着海子的诗,脑袋里想康德想的事情,兜里屁都没有,幻想自己是大国总理,去想影帝是怎么炼成的。

    自由是有代价的:聊聊这几年尝试的道路 现在不愿意写过多的技术文章了,一点是现在做的技术比较偏,写出来看的人也不多,二来是家庭事务比较繁多,没以前那么有时间写了.最近,园子里多了一些写经历的文章,我也将 ...

  5. [项目实施失败讨论Case] “凭心而论,在这家公司很敬业的工作了3年多,老板最后给我下的评语,大家都看看吧,千万别和我走同一条路!”(摘自csdn)

    [Case] “凭心而论,在这家公司很敬业的工作了3年多,老板最后给我下的评语,大家都看看吧,千万别和我走同一条路!”(摘自csdn) 原文:http://community.csdn.net/Exp ...

  6. Ant scp upload文件至linux server(用java调用Ant api)

    1.要准备的jar包:ant.jar,ant-jsch.jar code: package com.test.utils; import org.apache.tools.ant.Project; i ...

  7. git学习笔记(一)—— git环境搭建

    一.简介 Git是目前世界上最先进的分布式版本控制系统(没有之一). 首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库 ...

  8. HDU 1258 Sum It Up (DFS)

    Sum It Up Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total S ...

  9. 【MySQL】MySQL支持的数据类型

    1.整型 MySQL数据类型 含义(有符号) tinyint(m) 1个字节 范围(-128~127) smallint(m) 2个字节 范围(-32768~32767) mediumint(m) 3 ...

  10. WCF入门教程(四)通过Host代码方式来承载服务 一个WCF使用TCP协议进行通协的例子 jquery ajax调用WCF,采用System.ServiceModel.WebHttpBinding System.ServiceModel.WSHttpBinding协议 学习WCF笔记之二 无废话WCF入门教程一[什么是WCF]

    WCF入门教程(四)通过Host代码方式来承载服务 Posted on 2014-05-15 13:03 停留的风 阅读(7681) 评论(0) 编辑 收藏 WCF入门教程(四)通过Host代码方式来 ...