事件驱动模型的简单Java实现
事件驱动模型的原理不再赘述,Swing是不错的实现。别人也有不错的博文来说明原理。
本文的目的是提供一种简单的,可供参考的简短代码,用来帮助理解该模型。
Project Navigator

Event
事件通用接口:
- package org.joshua.event.events;
- public interface Event {
- }
Click事件:
- package org.joshua.event.events;
- public class ClickEvent implements Event {
- }
Double click事件:
- package org.joshua.event.events;
- public class DblClickEvent implements Event {
- }
Listener
事件监听器通用接口:
- package org.joshua.event.listener;
- import org.joshua.event.events.Event;
- public interface EventListener<T extends Event> {
- public void handleEvent(T event);
- }
Click事件监听器:
- package org.joshua.event.listener;
- import org.joshua.event.events.ClickEvent;
- public interface ClickEventHandler extends EventListener<ClickEvent> {
- }
Double Click事件监听器:
- package org.joshua.event.listener;
- import org.joshua.event.events.DblClickEvent;
- public interface DblClickEventHandler extends EventListener<DblClickEvent> {
- }
Event Source
事件源通用接口:
- package org.joshua.event.source;
- import org.joshua.event.events.Event;
- import org.joshua.event.listener.EventListener;
- public interface EventSource {
- void addEventListener(EventListener<? extends Event> listener);
- void removeEventListener(EventListener<? extends Event> listener);
- void notifyListeners(Event event);
- }
模拟的按钮控件:
- package org.joshua.event.source;
- import java.util.LinkedList;
- import java.util.List;
- import org.joshua.event.events.Event;
- import org.joshua.event.listener.EventListener;
- public class Button implements EventSource {
- protected List<EventListener<? extends Event>> listeners = new LinkedList<EventListener<? extends Event>>();
- @Override
- public void addEventListener(EventListener<? extends Event> listener) {
- listeners.add(listener);
- }
- @Override
- public void removeEventListener(EventListener<? extends Event> listener) {
- listeners.remove(listener);
- }
- @Override
- public void notifyListeners(Event event) {
- for (EventListener listener : listeners) {
- try {
- listener.handleEvent(event);
- } catch (ClassCastException e) {
- }
- }
- }
- }
Client
- package org.joshua.event;
- import org.joshua.event.events.ClickEvent;
- import org.joshua.event.events.DblClickEvent;
- import org.joshua.event.events.Event;
- import org.joshua.event.listener.ClickEventHandler;
- import org.joshua.event.listener.DblClickEventHandler;
- import org.joshua.event.source.Button;
- import org.junit.Before;
- import org.junit.Test;
- public class Client {
- private Event currentEvent;
- private Button button;
- @Before
- public void initComponent() {
- button = new Button();
- button.addEventListener(new ClickEventHandler() {
- @Override
- public void handleEvent(ClickEvent event) {
- System.out.println("Button was clicked!");
- }
- });
- button.addEventListener(new DblClickEventHandler() {
- @Override
- public void handleEvent(DblClickEvent event) {
- System.out.println("Button was double clicked!");
- }
- });
- }
- @Test
- public void testCommonEvents() {
- currentEvent = new ClickEvent();
- button.notifyListeners(currentEvent);
- currentEvent = new DblClickEvent();
- button.notifyListeners(currentEvent);
- }
- }
Button类中的notifyListener方法实现起来虽方便,利用了一把异常机制,但着实不推荐大家在项目中这样做。且不说性能问题,Listener的handleEvent方法里所有抛出的ClassCastException都需要重新包装。当然,我们可以使用annotation、限定类名等方式相对优雅地解决event和对应listener的mapping问题。
多线程事件处理机制
思路是用队列暂存事件,然后若干个事件分发器将事件分发给指定数量的事件处理线程处理。
- package com.joshua.test.event;
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.LinkedBlockingQueue;
- import com.joshua.test.event.event.Event;
- import com.joshua.test.event.event.EventType;
- import com.joshua.test.event.handler.CreateEventHandler;
- public class EventManager {
- private static final int EVENT_QUEUE_LENGTH = 1000;
- private static final int DISPATCHER_NUM = 2;
- private static final int EVENT_HANDLER_NUM = 10;
- public BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<Event>(EVENT_QUEUE_LENGTH);
- private ExecutorService eventHandlerPool;
- protected EventDispatcher createDispatcher() {
- EventDispatcher dispatcher = new EventDispatcher(this.eventQueue, this.eventHandlerPool);
- dispatcher.register(EventType.CREATE, CreateEventHandler.class);
- return dispatcher;
- }
- public void init() {
- eventHandlerPool = Executors.newFixedThreadPool(EVENT_HANDLER_NUM);
- }
- public void start() {
- for (int i = 0; i < DISPATCHER_NUM; i++) {
- createDispatcher().start();
- }
- }
- public void notify(Event event) {
- try {
- eventQueue.put(event);
- } catch (InterruptedException e) {
- }
- }
- }
- package com.joshua.test.event;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.concurrent.BlockingQueue;
- import java.util.concurrent.ExecutorService;
- import com.joshua.test.event.event.Event;
- import com.joshua.test.event.event.EventType;
- import com.joshua.test.event.handler.EventHandler;
- @SuppressWarnings("rawtypes")
- public class EventDispatcher {
- private final BlockingQueue<Event> eventQueue;
- private final ExecutorService eventHandlerPool;
- protected final Map<EventType, Class<? extends EventHandler>> eventDispatchers = new HashMap<EventType, Class<? extends EventHandler>>();
- private Thread eventHandlingThread;
- private volatile boolean stopped = false;
- public EventDispatcher(BlockingQueue<Event> eventQueue, ExecutorService eventHandlerPool) {
- this.eventQueue = eventQueue;
- this.eventHandlerPool = eventHandlerPool;
- System.out.println("Event dispatcher starting...");
- }
- Runnable createThread() {
- return new Runnable() {
- @Override
- public void run() {
- while (!stopped && !Thread.currentThread().isInterrupted()) {
- Event event;
- try {
- event = eventQueue.take();
- } catch (InterruptedException ie) {
- if (!stopped) {
- System.out.println("Dispatcher thread interrupted");
- ie.printStackTrace();
- }
- return;
- }
- if (event != null) {
- dispatch(event);
- }
- }
- }
- };
- }
- @SuppressWarnings("unchecked")
- protected void dispatch(Event event) {
- EventType type = event.getType();
- try {
- Class<? extends EventHandler> handlerClazz = eventDispatchers
- .get(type);
- if (handlerClazz != null) {
- EventHandler handler = handlerClazz.newInstance();
- handler.setEvent(event);
- eventHandlerPool.submit(handler);
- } else {
- throw new Exception("No handler for registered for " + type);
- }
- } catch (Throwable t) {
- System.err.println("Error in dispatcher thread");
- t.printStackTrace();
- System.exit(-1);
- }
- }
- public void register(EventType eventType,
- Class<? extends EventHandler> handler) {
- Class<? extends EventHandler> registeredHandler = eventDispatchers
- .get(eventType);
- System.out.println("Registering " + eventType + " for "
- + handler);
- if (registeredHandler == null) {
- eventDispatchers.put(eventType, handler);
- }
- }
- public void start() {
- eventHandlingThread = new Thread(createThread());
- eventHandlingThread.setName("AsyncDispatcher event handler");
- eventHandlingThread.start();
- System.out.println("Event dispatcher started!");
- }
- public void stop() {
- stopped = true;
- if (eventHandlingThread != null) {
- eventHandlingThread.interrupt();
- try {
- eventHandlingThread.join();
- } catch (InterruptedException ie) {
- System.out.println("Interrupted Exception while stopping");
- ie.printStackTrace();
- }
- }
- }
- }
事件驱动模型的简单Java实现的更多相关文章
- Java学习疑惑(8)----可视化编程, 对Java中事件驱动模型的理解
我们编写程序就是为了方便用户使用, 我觉得UI设计的核心就是简洁, 操作过于繁琐的程序让很大一部分用户敬而远之. 即使功能强大, 但是人们更愿意使用易于操作的软件. 近年流行起来的操作手势和逐渐趋于成 ...
- salesforce lightning零基础学习(二) lightning 知识简单介绍----lightning事件驱动模型
看此篇博客前或者后,看一下trailhead可以加深印象以及理解的更好:https://trailhead.salesforce.com/modules/lex_dev_lc_basics 做过cla ...
- Java I/O模型的简单说明
1.同步和异步 同步:如果有多个任务或者事件要发生,这些任务或者事件必须逐个地进行,一个事件或者任务的执行会导致整个流程的暂时等待,这些事件没有办法并发地执行,最简单的例子就是顺序的执行两个方法,当第 ...
- 事件驱动模型实例详解(Java篇)
或许每个软件从业者都有从学习控制台应用程序到学习可视化编程的转变过程,控制台应用程序的优点在于可以方便的练习某个语言的语法和开发习惯(如.net和java),而可视化编程的学习又可以非常方便开发出各类 ...
- Java内存模型JMM简单分析
参考博文:http://blog.csdn.net/suifeng3051/article/details/52611310 http://www.cnblogs.com/nexiyi/p/java_ ...
- (六)观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 本章我们讨论一个除前面的单例 ...
- 详解Spring事件驱动模型
转载自:http://jinnianshilongnian.iteye.com/blog/1902886#comments 事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理 ...
- 设计模式之 观察者模式详解(包含观察者模式JDK的漏洞以及事件驱动模型)
作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 本章我们讨论一个除前面的单例 ...
- spring 事件驱动模型简介
事件驱动模型简介 事件驱动模型也就是我们常说的观察者,或者发布-订阅模型:理解它的几个关键点: 首先是一种对象间的一对多的关系:最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方): ...
随机推荐
- 如何找到Firefox的收藏夹,就像IE一样,出现在网页的侧面
firefox有这个插件,安装后就可以 http://addons.mozine.cn/firefox/19/ All-In-OneSidebar ? 概述 All-In-OneSidebar ...
- 【DeepLearning】Exercise:Convolution and Pooling
Exercise:Convolution and Pooling 习题链接:Exercise:Convolution and Pooling cnnExercise.m %% CS294A/CS294 ...
- syslog远程日志存储/514端口【转】
昨天在抓包的时候,发现在514端口,有SYSLOG字段的东西,不知道是用来干啥的,现在来分析一下: 其实他是在电脑间用了syslog远程日志存储,他用udp监控了514端口的数据流,之后收集整理日志: ...
- zabbix邮件告警之 通过shell脚本发送告警
说明:本文讲如何通过shell脚本实现zabbix发送告警邮件,共有5步1.设置mailx账号:是配置mailx的发信账号2.zabbix服务器端编写邮件发送脚本:是增加zabbix的告警方式,增加通 ...
- Ant压缩与解压缩
package com.test.utils; import java.io.File; import java.io.FileOutputStream; import java.io.InputSt ...
- TensorFlow Google大会总结
一.概述 介绍TPU,需要使用XLA编译,否则没有做内部优化,无法达到加速的效果: TPU相关的性能分析器: 二.新版本的输入库 之前TensorFlow的输入方式: feed_dict: 太过于低效 ...
- k8s实战之数据卷(volume)
一.概述 数据卷用于实现容器持久化数据,k8s对于数据卷重新定义,提供了丰富强大的功能:数据卷分为三类: 本地数据卷,网络数据卷和信息数据卷 二.
- 【struts2】Struts2的系统架构
Struts2的官方文档里附带了Struts2的架构图,下面这张图上展示了Struts2的内部模块,以及它们的运行流程. 这张图上分了好多块,彼此之间相互联系,先浏览一下各块的名字,再留心一下运行图最 ...
- 黑客公布2012年最弱智密码Top25(转)
尽管弱密码对安全性的危害大家都知道,但是仍然有很多网民使用超弱密码.日前,黑客公布了一份密码文档,列出了今年最弱智密码. 根据 SplashData 公布的“年度最弱智密码 Top25”,和去年一样, ...
- 一步一步掌握java的线程机制(二)----Thread的生命周期
之前讲到Thread的创建,那是Thread生命周期的第一步,其后就是通过start()方法来启动Thread,它会执行一些内部的管理工作然后调用Thread的run()方法,此时该Thread就是a ...