我大概是當完兵之後才開始用 HandlerManager
作 event bus,目的當然是降低耦合度。起手 reference 是 tkcn 的這篇《利用 HandlerManager 實作共用的 Event Bus》,然後一直以來就爽爽用,沒出啥問題、也沒想過會出問題。今天在 review 別人的 code 才知道有 SimpleEventBus
,然後想知道這兩個到底有什麼差別、該用哪一個比較好?沒想到才剛打開 HandlerManager
的 source code,一開頭的 javadoc 就開始噴血:
application developers are strongly discouraged from using a HandlerManager instance as a global event dispatch mechanism.
WTF?不但不建議,而且是強烈不建議?GWT MVP 的文件都還是教用 HandlerManager
阿?
tkcn 建議我去找這段 javadoc 是什麼時候改的,於是考古了一下,發現 HandlerManager
是 2008.11.18 建的,然後上頭那段恐嚇文字是 2010.12.03 才加上去的(HandlerManager log)。
這下子就跑出另一個問題了:「為什麼?」
HandlerManager
裡頭還不是用了一個繼承 SimpleEventBus
的 Bus
然後以此 delegate…… 等等,有兩個 SimpleEventBus
?
一個是來自 com.google.gwt.event.shared
(以下簡稱 gwt.event
),一個是來自 com.google.web.bindery.event.shared
(以下簡稱 bindery.event
)。
gwt.event
的 SimpleEventBus
還是有一個 bindery.event
的 SimpleEventBus
的 instance(變數名稱為 real
)。以 fireEvent()
來說,如果要 fire 的 event 是 bindery.event
的 Event
就用 real
來處理,如果要 fire 的 event 是 GwtEvent
(在 gwt.event
下),則改呼叫 (gwt.event
)EventBus.castFireEvent()
。castFireEvent()
的程式碼感覺單純
protected void castFireEvent(GwtEvent<?> event) {
try {
fireEvent((Event<?>) event);
} catch (com.google.web.bindery.event.shared.UmbrellaException e) {
throw new UmbrellaException(e.getCauses());
}
}
GwtEvent
一樣也是繼承 Event
,帳面上看起來根本不會有炸 exception 的可能?而且最後還是呼叫 bindery.event
的那個 fireEvent()
,也就是說,不管怎樣最後處理的都是那個 bindery.event
的 SimpleEventBus
(變數 real
)。這一切到底有什麼意義?
從 gwt.event
的 SimpleEventBus
看起來:
Wraps {com.google.web.bindery.event.shared.SimpleEventBus} for legacy compatibility.
bindery.event
下的 class 應該都是歷史的眼淚。甚至 gwt.event
的 EventBus.fireEvent(Event<?>)
還會炸有下列訊息的 UnsupportedOperationException
:
Subclass responsibility. This class is a legacy wrapper for com.google.web.bindery.event.shared.EventBus. Use that directly, or try com.google.gwt.event.shared.SimpleEventBus
先面有提到,SimpleEventBus
有 override 掉用,所以用起來也沒事情。這樣看起來 gwt.event
底下才是未來,bindery.event
只是忘記還沒法拋棄的舊情人。正當一切都覺得很踏實的時候,GwtEvent
的 javadoc 馬上來了一記回馬槍:
There is no need for an application's custom event types to extend GwtEvent. Prefer {@link Event} instead.
既然建議改用(bindery.event
)Event
,那 gwt.event
的那個 EventBus.fireEvent(Event<?>)
為什麼又要預設這種行為?你為什麼要讓他留在 bindery.event
的 package 底下?
整理到這邊,我就放棄了 [死]。
不負責任的結論
截至目前(2.6.1)的版本看來,要不要繼續用 HandlerManager
、GwtEvent
還是 bindery.event
下的東西,學理上都不會出事、效果也幾乎一模一樣。至於 package 分割的方式、未來這個部份會不會有所改變(謎之聲:應該不會),那等炸了再說吧……
說不定就算寫信去問 GWT 委員會,他們也都忘記有這件事了……
順便佔篇幅的附錄
bindery.event
的 Event.Type
的 hashCode
是這樣來的:
private static int nextHashCode;
private final int index;
public Type() {
index = ++nextHashCode;
}
public final int hashCode() {
return index;
}
實際上效率應該會不錯,無論是用它當 key 取出對應的 handler 們、還是 new 一個新的 type、單純看 event / handler 的實做 code 也都很 Java。不過底層的 code 用 Java 的角度大概會被詰譙到死(連個 synchronized 都沒有是哪招?)。只能說 GWT 寫起來還是並不完全等同 Java,在看不到的底層就可以用、也應該要用 JS 的思維亂來 XDDD
沒有留言:
張貼留言