[GWT] HandlerManager 与两个 event package

楼主: PsMonkey (痞子军团团长)   2014-05-16 08:41:35
blog 版:
http://blog.dontcareabout.us/2014/05/handlermanager-event-package.html
BBS 版(大抵上)用 markdown 语法撰写
______________________________________________________________________
我大概是当完兵之后才开始用 `HandlerManager` 作 event bus,
目的当然是降低耦合度。
起手 reference 是 tkcn 的这篇
《[利用 HandlerManager 实作共用的 Event Bus][tkcn ref]》,
然后一直以来就爽爽用,没出啥问题、也没想过会出问题。
今天在 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 ref]: http://tkcnandy.blogspot.tw/2009/12/
handlermanager-event-bus.html
tkcn 建议我去找这段 javadoc 是什么时候改的,
于是考古了一下,发现 `HandlerManager` 是 2008.11.18 建的,
然后上头那段恐吓文字是 2010.12.03 才加上去的
([HandlerManager log])。
[HandlerManager log]: https://gwt.googlesource.com/gwt/+/
58c04717a6ec18dd65adda0e3b6b6a624a3b7ca5%5E%21/#F0
这下子就跑出另一个问题了:“为什么?”
`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
作者: swpoker (swpoker)   2014-05-16 09:15:00
相容阿~不然就通通砍掉重练!!!
楼主: PsMonkey (痞子军团团长)   2014-05-16 09:35:00
能砍掉重练是种幸福 XD
作者: swpoker (swpoker)   2014-05-16 13:35:00
有些东西不能砍掉重练阿 例如老二之类的

Links booklink

Contact Us: admin [ a t ] ucptt.com