(從MMO發言開發者的視角)
我發現,爲了可伸縮性,您可能需要在多個線程中處理事件處理;我通常有這樣一個規律:
public class Event { EventType getType(); }
// extend Event for special cases that require additional attributes…
public class EventDispatcher {
Map<Class<? extends Event>, List<Observer>> observers;
void send (final Event e) {
for (Observer o : observers.get(e.getClass())) {
o.receiveEvent (e);
}
}
}
或者,你可以使用一個enum
:
public enum EventType { … } ;
…
Map <EventType,List<Observer>> observers;
…
for (Observer o : observers.get(e.getEventType())) …
當你成長到處理更多的觀察員,您可能需要分區的事件處理和/或者讓它在其他線程中運行。 EventDispatcher.send(Event)
方法爲您提供了一個擴展該方法的地方,例如放入空間分區(由於距離太遠無法檢測到此事件),或者將Event對象注入隊列以便在其他線程上進行異步處理,其中事件處理程序不會影響產生事件的線程。
我們最初開始使用這個模型來處理事件傳播回人類玩家(所以網絡代碼在自己的線程上同步運行),但是發現隊列系統也幫助加快了AI和物理傳播。
可能的缺點是你必須在你的Observer類上有一個switch/case過濾器。這通常屬於一個普通的基類,假設你有相當少量的EventType枚舉。在早期的Romance MMO內核迭代中(爲了向後兼容,仍然支持1.1代碼庫),我們使用接口來接收各種事件。 (基類掛鉤到這些一般的事件接收器 - 我們稱之爲行動從UI事件處理程序來區分)
public interface EventFooHandler {
public void handleEventFoo (int bar, int baz);
};
public class SomeObject implements EventFooHandler …
也許這些接口是你的意思這一般是「噸空類的?」 「通俗的Java正確的方式來做它」的東西,在你自己的堆棧/線程中運行;例如我相信Swing以這種方式大量使用「回調函數」,就像任何其他標準Java庫一樣。
當然,如果你不想簡單地實現每個觀察接口,您可以使用匿名類...
getEventDispatcher().registerForEventFoo
(new EventFooHandler {
public void handleEventFoo (int bar, int baz) {
this.doGribble (bar + 2, baz);
}});
如果你不咬咬牙,潛入實體系統(我肯定有人肯定會彈出並插入一個,可能會提到不可變狀態的樂趣,他們建議轉換到Erlang爲您的下一個項目50%的可能性:-)),我傾向於類似於前者。 「統一事件」系統允許「管道」是正交的,事件→觀察者路由在一個地方被改變,並且隨着時間的推移,不會在觀察者上傳播每種事件類型的雜項方法。
爲什麼不使用PropertyChangeSupport/PropertyChangeListener,或者模擬它的作用? – 2011-12-16 20:50:35