• 事件驱动模型的简单Java实现


    事件驱动模型的原理不再赘述,Swing是不错的实现。别人也有不错的博文来说明原理。

    本文的目的是提供一种简单的,可供参考的简短代码,用来帮助理解该模型。

    Project Navigator

    Event

    事件通用接口:

    Java代码  收藏代码
    1. package org.joshua.event.events;  
    2.   
    3. public interface Event {  
    4. }  

    Click事件:

    Java代码  收藏代码
    1. package org.joshua.event.events;  
    2.   
    3. public class ClickEvent implements Event {  
    4.   
    5. }  

    Double click事件:

    Java代码  收藏代码
    1. package org.joshua.event.events;  
    2.   
    3. public class DblClickEvent implements Event {  
    4.   
    5. }  

    Listener

    事件监听器通用接口:

    Java代码  收藏代码
    1. package org.joshua.event.listener;  
    2.   
    3. import org.joshua.event.events.Event;  
    4.   
    5. public interface EventListener<T extends Event> {  
    6.       
    7.     public void handleEvent(T event);  
    8.   
    9. }  

    Click事件监听器:

    Java代码  收藏代码
    1. package org.joshua.event.listener;  
    2.   
    3. import org.joshua.event.events.ClickEvent;  
    4.   
    5.   
    6. public interface ClickEventHandler extends EventListener<ClickEvent> {  
    7.   
    8. }  

    Double Click事件监听器:

    Java代码  收藏代码
    1. package org.joshua.event.listener;  
    2.   
    3. import org.joshua.event.events.DblClickEvent;  
    4.   
    5. public interface DblClickEventHandler extends EventListener<DblClickEvent> {  
    6.   
    7. }  

    Event Source

    事件源通用接口:

    Java代码  收藏代码
    1. package org.joshua.event.source;  
    2.   
    3. import org.joshua.event.events.Event;  
    4. import org.joshua.event.listener.EventListener;  
    5.   
    6. public interface EventSource {  
    7.   
    8.     void addEventListener(EventListener<? extends Event> listener);  
    9.       
    10.     void removeEventListener(EventListener<? extends Event> listener);  
    11.       
    12.     void notifyListeners(Event event);  
    13.   
    14. }  

    模拟的按钮控件:

    Java代码  收藏代码
    1. package org.joshua.event.source;  
    2.   
    3. import java.util.LinkedList;  
    4. import java.util.List;  
    5.   
    6. import org.joshua.event.events.Event;  
    7. import org.joshua.event.listener.EventListener;  
    8.   
    9. public class Button implements EventSource {  
    10.   
    11.     protected List<EventListener<? extends Event>> listeners = new LinkedList<EventListener<? extends Event>>();  
    12.   
    13.     @Override  
    14.     public void addEventListener(EventListener<? extends Event> listener) {  
    15.         listeners.add(listener);  
    16.     }  
    17.   
    18.     @Override  
    19.     public void removeEventListener(EventListener<? extends Event> listener) {  
    20.         listeners.remove(listener);  
    21.     }  
    22.   
    23.     @Override  
    24.     public void notifyListeners(Event event) {  
    25.         for (EventListener listener : listeners) {  
    26.             try {  
    27.                 listener.handleEvent(event);  
    28.             } catch (ClassCastException e) {  
    29.             }  
    30.         }  
    31.     }  
    32.   
    33. }  

    Client

    Java代码  收藏代码
    1. package org.joshua.event;  
    2.   
    3. import org.joshua.event.events.ClickEvent;  
    4. import org.joshua.event.events.DblClickEvent;  
    5. import org.joshua.event.events.Event;  
    6. import org.joshua.event.listener.ClickEventHandler;  
    7. import org.joshua.event.listener.DblClickEventHandler;  
    8. import org.joshua.event.source.Button;  
    9. import org.junit.Before;  
    10. import org.junit.Test;  
    11.   
    12. public class Client {  
    13.       
    14.     private Event currentEvent;  
    15.       
    16.     private Button button;  
    17.       
    18.       
    19.     @Before  
    20.     public void initComponent() {  
    21.           
    22.         button = new Button();  
    23.           
    24.         button.addEventListener(new ClickEventHandler() {  
    25.             @Override  
    26.             public void handleEvent(ClickEvent event) {  
    27.                 System.out.println("Button was clicked!");  
    28.             }  
    29.         });  
    30.           
    31.         button.addEventListener(new DblClickEventHandler() {  
    32.             @Override  
    33.             public void handleEvent(DblClickEvent event) {  
    34.                 System.out.println("Button was double clicked!");  
    35.             }  
    36.         });  
    37.           
    38.     }  
    39.       
    40.     @Test  
    41.     public void testCommonEvents() {  
    42.         currentEvent = new ClickEvent();  
    43.         button.notifyListeners(currentEvent);  
    44.           
    45.         currentEvent = new DblClickEvent();  
    46.         button.notifyListeners(currentEvent);  
    47.     }  
    48.   
    49. }  

     Button类中的notifyListener方法实现起来虽方便,利用了一把异常机制,但着实不推荐大家在项目中这样做。且不说性能问题,Listener的handleEvent方法里所有抛出的ClassCastException都需要重新包装。当然,我们可以使用annotation、限定类名等方式相对优雅地解决event和对应listener的mapping问题。

    多线程事件处理机制

    思路是用队列暂存事件,然后若干个事件分发器将事件分发给指定数量的事件处理线程处理。

    Java代码  收藏代码
    1. package com.joshua.test.event;  
    2.   
    3. import java.util.concurrent.BlockingQueue;  
    4. import java.util.concurrent.ExecutorService;  
    5. import java.util.concurrent.Executors;  
    6. import java.util.concurrent.LinkedBlockingQueue;  
    7.   
    8. import com.joshua.test.event.event.Event;  
    9. import com.joshua.test.event.event.EventType;  
    10. import com.joshua.test.event.handler.CreateEventHandler;  
    11.   
    12. public class EventManager {  
    13.   
    14.     private static final int EVENT_QUEUE_LENGTH = 1000;  
    15.     private static final int DISPATCHER_NUM = 2;  
    16.     private static final int EVENT_HANDLER_NUM = 10;  
    17.       
    18.     public BlockingQueue<Event> eventQueue = new LinkedBlockingQueue<Event>(EVENT_QUEUE_LENGTH);  
    19.     private ExecutorService eventHandlerPool;  
    20.       
    21.     protected EventDispatcher createDispatcher() {  
    22.         EventDispatcher dispatcher = new EventDispatcher(this.eventQueue, this.eventHandlerPool);  
    23.         dispatcher.register(EventType.CREATE, CreateEventHandler.class);  
    24.         return dispatcher;  
    25.     }  
    26.       
    27.     public void init() {  
    28.         eventHandlerPool = Executors.newFixedThreadPool(EVENT_HANDLER_NUM);  
    29.     }  
    30.       
    31.     public void start() {  
    32.         for (int i = 0; i < DISPATCHER_NUM; i++) {  
    33.             createDispatcher().start();  
    34.         }  
    35.     }  
    36.       
    37.     public void notify(Event event) {  
    38.         try {  
    39.             eventQueue.put(event);  
    40.         } catch (InterruptedException e) {  
    41.         }  
    42.     }  
    43.   
    44. }  
    Java代码  收藏代码
    1. package com.joshua.test.event;  
    2.   
    3. import java.util.HashMap;  
    4. import java.util.Map;  
    5. import java.util.concurrent.BlockingQueue;  
    6. import java.util.concurrent.ExecutorService;  
    7.   
    8. import com.joshua.test.event.event.Event;  
    9. import com.joshua.test.event.event.EventType;  
    10. import com.joshua.test.event.handler.EventHandler;  
    11.   
    12. @SuppressWarnings("rawtypes")  
    13. public class EventDispatcher {  
    14.   
    15.     private final BlockingQueue<Event> eventQueue;  
    16.     private final ExecutorService eventHandlerPool;  
    17.     protected final Map<EventType, Class<? extends EventHandler>> eventDispatchers = new HashMap<EventType, Class<? extends EventHandler>>();  
    18.     private Thread eventHandlingThread;  
    19.   
    20.     private volatile boolean stopped = false;  
    21.   
    22.     public EventDispatcher(BlockingQueue<Event> eventQueue, ExecutorService eventHandlerPool) {  
    23.         this.eventQueue = eventQueue;  
    24.         this.eventHandlerPool = eventHandlerPool;  
    25.         System.out.println("Event dispatcher starting...");  
    26.     }  
    27.   
    28.     Runnable createThread() {  
    29.         return new Runnable() {  
    30.             @Override  
    31.             public void run() {  
    32.                 while (!stopped && !Thread.currentThread().isInterrupted()) {  
    33.                     Event event;  
    34.                     try {  
    35.                         event = eventQueue.take();  
    36.                     } catch (InterruptedException ie) {  
    37.                         if (!stopped) {  
    38.                             System.out.println("Dispatcher thread interrupted");  
    39.                             ie.printStackTrace();  
    40.                         }  
    41.                         return;  
    42.                     }  
    43.                     if (event != null) {  
    44.                         dispatch(event);  
    45.                     }  
    46.                 }  
    47.             }  
    48.         };  
    49.     }  
    50.   
    51.     @SuppressWarnings("unchecked")  
    52.     protected void dispatch(Event event) {  
    53.         EventType type = event.getType();  
    54.         try {  
    55.             Class<? extends EventHandler> handlerClazz = eventDispatchers  
    56.                     .get(type);  
    57.             if (handlerClazz != null) {  
    58.                 EventHandler handler = handlerClazz.newInstance();  
    59.                 handler.setEvent(event);  
    60.                 eventHandlerPool.submit(handler);  
    61.             } else {  
    62.                 throw new Exception("No handler for registered for " + type);  
    63.             }  
    64.         } catch (Throwable t) {  
    65.             System.err.println("Error in dispatcher thread");  
    66.             t.printStackTrace();  
    67.             System.exit(-1);  
    68.         }  
    69.     }  
    70.   
    71.     public void register(EventType eventType,  
    72.             Class<? extends EventHandler> handler) {  
    73.         Class<? extends EventHandler> registeredHandler = eventDispatchers  
    74.                 .get(eventType);  
    75.         System.out.println("Registering " + eventType + " for "  
    76.                 + handler);  
    77.         if (registeredHandler == null) {  
    78.             eventDispatchers.put(eventType, handler);  
    79.         }  
    80.     }  
    81.   
    82.     public void start() {  
    83.         eventHandlingThread = new Thread(createThread());  
    84.         eventHandlingThread.setName("AsyncDispatcher event handler");  
    85.         eventHandlingThread.start();  
    86.         System.out.println("Event dispatcher started!");  
    87.     }  
    88.   
    89.     public void stop() {  
    90.         stopped = true;  
    91.         if (eventHandlingThread != null) {  
    92.             eventHandlingThread.interrupt();  
    93.             try {  
    94.                 eventHandlingThread.join();  
    95.             } catch (InterruptedException ie) {  
    96.                 System.out.println("Interrupted Exception while stopping");  
    97.                 ie.printStackTrace();  
    98.             }  
    99.         }  
    100.     }  
    101.   
    102. }  

     
     

  • 相关阅读:
    Qt Creator编译问题
    『重构--改善既有代码的设计』读书笔记----Move Method
    『重构--改善既有代码的设计』读书笔记----Substitute Algorithm
    『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object
    『重构--改善既有代码的设计』读书笔记----Remove Assignments to Parameters
    『重构--改善既有代码的设计』读书笔记----Split Temporary Variable
    Qt信号槽连接在有默认形参下的情况思考
    巧用Session Manager还原Firefox丢失会话
    『重构--改善既有代码的设计』读书笔记----代码坏味道【5】
    『重构--改善既有代码的设计』读书笔记----代码坏味道【4】
  • 原文地址:https://www.cnblogs.com/tiancai/p/9908584.html
Copyright © 2020-2023  润新知