1. 程式人生 > >事件驅動模型的簡單Java實現

事件驅動模型的簡單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. }