注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

0与1构筑世界,程序员创造时代

软件架构设计 Java编程

 
 
 

日志

 
 

事件驱动 | Event Driven  

2013-09-03 21:00:46|  分类: 软件架构与设计 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

提到事件驱动,熟悉Java的童鞋会想到Java Swing中的事件模型:按钮的按下、释放;鼠标在窗口的移入、移出;输入框被做焦点、失去焦点、输入,都会要求编写一个事件监听器。
事件驱动有几个用途:1)实现模块间的松耦合。 2)将一个大的业务场景拆分成几个独立的小部分。 3)提供扩展点,实现插件机制的功能。 4)用于异步操作场景。
例如,一个用户登陆的业务场景:用户执行登陆操作后,会进行用于登陆成功率的统计日志输出,如果登陆成功需要通知用户在线模块某一个用户成功登陆了。
用事件驱动非常方便解决上述问题:执行登陆操作后,产生一个登陆事件,编写两件事件监听器(一个处理登陆成功率的统计日志输出,一个通知用户在线模块)注册到登陆事件。如果后续在用户执行登陆后还有新的业务需求,只需编写新的事件监听器注册到登陆事件。这样的做法符合开闭原则,实现新的功能不影响已有功能。如果要移除某个功能点,直接移除对应的事件监听器。

如果查找事件驱动的实现机制,网上查到的大部分都是类似于下面的“经典事件驱动模式”的说明。但在实际的业务场景中,这样的实现不能满足需求,后面有一个"改进版事件驱动模式"。当然,需要再进一步改进才能满足实际中的需求,例如:异步执行,线程池,事件与事件监听器的注册配置,运行状态监控等等。

经典事件驱动模式

经典的事件驱动有三个基本元素:
  • 事件源:负责事件监听器的管理,创建并派发事件。
  • 事件监听器:接收并处理事件。
  • 事件。
事件驱动模式 | Event Driven Pattern - 傲风 - 宝剑锋从磨砺出 梅花香自苦寒来
 
其实现的Java源码如下:
/**
 * 事件
 @author aofeng <aofengblog@163.com>
 */
public class Event {

    private Object data;
    
    public Event(Object obj){
        this.data = obj;
    }

    public Object getData() {
        return data;
    }
}

/**
 * 事件监听器(监听一个或多个事件并进行具体的处理)
 
 @author aofeng <aofengblog@163.com>
 */
public interface EventListener {

    /**
     * 处理事件
     
     @param event 事件
     */
    public void execute(Event event);

}

import java.util.ArrayList;
import java.util.List;

/**
 * 事件源(事件发送者)
 
 @author aofeng <aofengblog@163.com>
 */
public class EventSource {

    private List<EventListener> listeners = new ArrayList<EventListener>();
    
    public EventSource() {

    }

    /**
     * 添加事件监听器
     
     @param listener 事件监听器
     */
    public boolean addListener(EventListener listener) {
        return listeners.add(listener);
    }

    /**
     * 移除事件监听器
     
     @param listener 移除事件监听器
     */
    public boolean removeListener(EventListener listener) {
        return listeners.remove(listener);
    }

    /**
     * 派发事件
     
     @param data 事件
     */
    public void fire(Object data) {
        for (EventListener listener : listeners) {
            listener.execute(new Event(data));
        }
    }

}


/**
 * 事件驱动调用示例
 @author aofeng <aofengblog@163.com>
 */
public class ClientMain {

    public static void main(String[] args) {
        EventSource eventSource = new EventSource();
        eventSource.addListener(new HelloWorldListener());
        eventSource.addListener(new SimpleListener());
        eventSource.fire("hello, world!");
    }

    public static class HelloWorldListener implements EventListener {
        @Override
        public void execute(Event event) {
            System.out.println("监听器:"+this +  "接收到事件,事件附带的数据:" + event.getData());
        }
        
    }
    
    public static class SimpleListener implements EventListener {
        @Override
        public void execute(Event event) {
            System.out.println("监听器:"+this +  "接收到事件,事件附带的数据:" + event.getData());
        }
        
    }

}

执行ClientMain类后的结果类似如下:
监听器:ClientMain$HelloWorldListener@45bab50a接收到事件,事件附带的数据:hello, world!
监听器:ClientMain$SimpleListener@7150bd4d接收到事件,事件附带的数据:hello, world!

改进版事件驱动模式

在经典版的基础上,将EventSource按职责进行拆分,一部分(EventSource)负责事件派分,另一部分(EventManagement)负责事件的管理(添加事件、移除事件、获取指定事件的监听器列表)。并且实现了向不同的事件注册各自的监听器。
事件驱动模式 | Event Driven Pattern - 傲风 - 宝剑锋从磨砺出 梅花香自苦寒来
  

/**
 * 事件
 
 @author aofeng <aofengblog@163.com>
 */
public class Event {

    // 事件附带的数据
    private Object data;
    
    // 事件类型
    private String eventType;
    
    public Event(String eventType, Object obj){
        this.eventType = eventType;
        this.data = obj;
    }

    public Object getData() {
        return this.data;
    }
    
    public String getEventType() {
        return this.eventType;
    }

}


/**
 * 事件监听器(监听一个或多个事件并进行具体的处理)
 
 @author aofeng <aofengblog@163.com>
 */
public interface EventListener {

   /**
     * 处理事件
    
     @param event    事件
     */
    public void execute(Event event);

}

import java.util.List;

/**
 * 事件源(事件发送者)
 
 @author aofeng <aofengblog@163.com>
 */
public class EventSource {

    // 事件管理器
    private EventManagement eventManagement;;
    
    public EventSource(EventManagement eventManagement){
        this.eventManagement = eventManagement;
    }

   /**
     * 派发事件
     
     @param data 事件
     */
    public void fire(Event event) {
        if (null == event) {
            return;
        }
        
        List<EventListener> listeners = eventManagement.getEventListeners(event.getEventType());
        if (null == listeners) {
            return;
        }
        
        for (EventListener listener : listeners) {
            listener.execute(event);
        }
    }

}

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 事件管理器。负责事件监听器的注册和移除操作,并提供获取指定事件的监听器列表功能。
 
 @author aofeng <aofengblog@163.com>
 */
public class EventManagement {

    private Map<String, List<EventListener>> map = new HashMap<String, List<EventListener>>();
    
    public EventManagement(){
        
    }

   /**
     * 向指定事件添加一个监听器
    
     @param eventType 事件类型
     * @param listener 事件监听器
     @return 添加成功返回true;添加失败返回false
     */
    public boolean addListener(String eventType, EventListener listener){
        List<EventListener> listeners = map.get(eventType);
        if (null == listeners) {
            listeners = new ArrayList<EventListener>();
        }
        boolean result = listeners.add(listener);
        map.put(eventType, listeners);
       
      return result;
    }

   /**
     * 移除事件的某一个监听器
    
     @param eventType 事件类型
     @param listener 事件监听器
     @return 移除成功返回true;移除失败返回false
     */
    public boolean removeListener(String eventType, EventListener listener){
        List<EventListener> listeners = map.get(eventType);
        if (null != listeners) {
            return listeners.remove(listener);
        }
        
        return false;
    }

   /**
     * 获取指定事件的监听器
    
     @param eventType 事件类型
     @return 如果指定的事件没有监听器返回null;否则返回监听器列表
     */
    public List<EventListener> getEventListeners(String eventType) {
        return map.get(eventType);
    }

}

/**
 * 事件驱动调用示例
 @author aofeng <aofengblog@163.com>
 */
public class ClientMain {

    public static void main(String[] args) {
        EventManagement eventManagement = new EventManagement();
        eventManagement.addListener("read"new HelloWorldListener());
        eventManagement.addListener("write"new SimpleListener());
        
        EventSource eventSource = new EventSource(eventManagement);
        eventSource.fire(new Event("read""this is a read event"));
        eventSource.fire(new Event("write""this is a write event"));
    }

    public static class HelloWorldListener implements EventListener {
        @Override
        public void execute(Event event) {
            System.out.println("监听器:"+this +  "接收到事件,事件类型是:" 
                    + event.getEventType() ", 事件附带的数据:" + event.getData());
        }
        
    }
    
    public static class SimpleListener implements EventListener {
        @Override
        public void execute(Event event) {
            System.out.println("监听器:"+this +  "接收到事件,事件类型是:" 
                    + event.getEventType() ", 事件附带的数据:" + event.getData());
        }
    }

}

执行ClientMain类后的结果类似如下:
监听器:ClientMain$HelloWorldListener@64c3c749接收到事件,事件类型是:read, 事件附带的数据:this is a read event
监听器:ClientMain$SimpleListener@6bbc4459接收到事件,事件类型是:write, 事件附带的数据:this is a write event


<正文结束>
文章声明


作者:傲风(aofengblog@163.com)       编写时间:2013年09月01日

网址:http://aofengblog.blog.163.com

作者保留所有权利,转载请保留文章全部内容或者说明原作者和转载地址!


  评论这张
 
阅读(1245)| 评论(1)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017