2014-04-04 117 views
0

我寫事件源模板我的課:事件來源:短道火災事件

public class EventSource<E> { 
    protected ArrayList<E> listeners = new ArrayList<E>(); 

    public void addListener(E listener) 
    { 
    listeners.add(listener); 
    } 

    public void removeListener(E listener) 
    { 
    listeners.remove(listener); 
    } 
} 

觸發事件我需要調用是這樣的:

for(SomeListener listener: listeners) 
    listener.onSomeEvent(); 

這看起來相當醜陋的事件發生。有沒有一種方法來調用一些短這樣的:

fire(SomeListener.onSomeEvent) 

fire(onSomeEvent) 

我已經找到3個解決方案:

我使用Java反射和傳遞方法的名稱作爲參數傳遞給在模板中的一些方法,這將調用此方法對所有的聽衆。但是我認爲它是低效的,因爲需要解析字符串(方法名稱)。以及如何以不醜的方式傳遞參數 - 問題依然存在。

II使用的所有方法的名稱相同,但通過不同的參數:

public struct SomeEvent1 
{ 
    int someData; 
} 

public struct SomeEvent2 
{ 
    int someAnotherData; 
    double probablyMoreData; 
} 

public interface SomeListener 
{ 
    public void fire(SomeEvent1 e); 
    public void fire(SomeEvent2 e); 
} 

但是,它需要建立這個事件結構,即使我不需要任何參數。

III使用授權。想象一下,SomeEventSource擴展了EventSource。現在,我可以調用onSomeEventI(),因爲我寫了一首歌SomeEventSource這些方法:

public void onSomeEventI() 
{ 
    for(SomeListener listener: listeners) 
    listener.onSomeEventI(); 
} 

但我不能寫在通用EventSource的那些方法,因爲它是監聽器無關。在SomeEventSource中編寫這些方法使通用的EventSource比無用的更加無用。

問題依然存在:如何在短時間內引發事件?

+0

嗯......使用泛型確實不適用於通用事件處理。看看Java的Java類Observer和Observable。他們不是最好的,但也許你可以接管一些零件。 – Seelenvirtuose

+0

是的,Observer - Observerable比寫自己的東西好。但它與方法(II)具有相同的缺點。如果有某種東西像std :: bind(我來自C++)綁定到一個函數並將其作爲參數傳遞。 – Deepscorn

+0

Java 8? Lambda表達式? – Seelenvirtuose

回答

2

我想一般事件API應包括以下幾件事:

  1. 類型安全,避免活動/事件類型類的鑄造 - 它會節省你意想不到的造型異常的未來。
  2. 開發者友好。 API應該簡短而甜蜜。您應該能夠輕鬆地在您的IDE中找到正確的偵聽器(例如Intellij IDEA或Eclipse)。類型安全會給你。
  3. 添加新的事件類型應該既簡單又快速。
  4. 事件結構應該是可重用的。

這裏是可能的方法之一:

創建基礎事件和更復雜的事件結構。

class BaseEvent { 
} 

class ComplexEvent extends BaseEvent { 
    int importantData; 
    public ComplexEvent(int i) { 
     importantData = i; 
    } 
} 

的EventType創建一個單獨的類,使每個事件類型依賴於事件。我們現在可以爲我們的事件類型重用現有的結構。在不破壞現有代碼的情況下添加新事件也很容易。

final class EventType<E> { 
    private EventType(){} 
    public final static EventType<BaseEvent> SimpleEvent = new EventType<BaseEvent>(); 
    public final static EventType<BaseEvent> SimpleEvent2 = new EventType<BaseEvent>(); 
    public final static EventType<ComplexEvent> ComplexEvent1 = new EventType<ComplexEvent>(); 
    public final static EventType<ComplexEvent> ComplexEvent2 = new EventType<ComplexEvent>(); 
} 

根據事件創建偵聽器作爲通用接口。

interface Listener<E extends BaseEvent> { 
    void handle(E event); 
} 

使用的EventSource在這個班,註冊指定事件類型的監聽器。

class EventSource { 

    private final Map<EventType, List<Listener<? extends BaseEvent>>> listenersMap = new HashMap<EventType, List<Listener<? extends BaseEvent>>>(); 

    public <E extends BaseEvent> void addListener(EventType<E> eventType, Listener<E> listener) { 
     listeners(eventType).add(listener); 
    } 

    public <E extends BaseEvent> void fire(EventType<E> eventType, E event) { 
     for (Listener listener : listeners(eventType)) { 
      listener.handle(event); 
     } 
    } 

    private List<Listener<? extends BaseEvent>> listeners(EventType eventType) { 
     if (listenersMap.containsKey(eventType)) { 
      return listenersMap.get(eventType); 
     } else { 
      List<Listener<? extends BaseEvent>> listenersList = new ArrayList(); 
      listenersMap.put(eventType, listenersList); 
      return listenersList; 
     } 
    } 

} 

檢查API的使用情況,它允許我們在Listener的實現中獲得正確的事件結構。

public static void main(String[] args) { 
     EventSource eventSource = new EventSource(); 
     eventSource.addListener(EventType.SimpleEvent, new Listener<BaseEvent>() { 
      @Override 
      public void handle(BaseEvent event) { 
       log.info("Simple 1 handled!"); 
      } 
     }); 
     eventSource.addListener(EventType.SimpleEvent2, new Listener<BaseEvent>() { 
      @Override 
      public void handle(BaseEvent event) { 
       log.info("Simple 2 handled!"); 
      } 
     }); 
     // compile error! we must handle ComplexEvent type 
//  eventSource.addListener(EventType.ComplexEvent1, new Listener<BaseEvent>() { 
//   @Override 
//   public void handle(BaseEvent event) { 
//    log.info("Complex 1 handled!"); 
//   } 
//  }); 
     eventSource.addListener(EventType.ComplexEvent1, new Listener<ComplexEvent>() { 
      @Override 
      public void handle(ComplexEvent event) { 
       log.info("Complex 1 handled!" + event.importantData); 
      } 
     }); 
     eventSource.addListener(EventType.ComplexEvent2, new Listener<ComplexEvent>() { 
      @Override 
      public void handle(ComplexEvent event) { 
       log.info("Complex 2 handled!" + event.importantData); 
      } 
     }); 
     eventSource.fire(EventType.SimpleEvent, new BaseEvent()); 
     eventSource.fire(EventType.SimpleEvent2, new BaseEvent()); 
     eventSource.fire(EventType.ComplexEvent1, new ComplexEvent(1)); 
     eventSource.fire(EventType.ComplexEvent2, new ComplexEvent(2)); 
     // compile error! we must fire ComplexEvent to our listeners 
     //eventSource.fire(EventType.ComplexEvent1, new BaseEvent()); 
    } 

您還可以添加一個速記fire調用EventSource當你不需要通過任何具體的數據

public <E extends BaseEvent> void fire(EventType<E> eventType) { 
    fire(eventType, (E) new BaseEvent()); 
} 

並從客戶端代碼一樣簡單使用它:

eventSource.fire(EventType.SimpleEvent); 
+0

非常感謝!而已! – Deepscorn