在许多标准Java库中(尤其是在AWT / Swing中),您可以找到以下EventListener / Event模式:
interface FooEventListener {
void fooDidBar(FooEvent e);
void fooDidBaz(FooEvent e);
void fooDidQux(FooEvent e);
}
而且,在FooEvent
中,您还可以找到
public class FooEvent {
static int FOO_DID_BAR = 1;
static int FOO_DID_BAZ = 2;
static int FOO_DID_QUX = 3;
// ...
public int getID(); // one of the above constants
}
这似乎是多余的。为什么要做出这个决定?在调用的特定方法中以及在作为该方法的参数传递的事件中具有此信息的优点是什么?
示例:
答案 0 :(得分:1)
我认为原因是:
1)所有AWT / Swing事件都扩展AWTEvent
,并且需要为其父构造函数提供事件id。传统AWT代码库和@MadProgrammer提到的事件调度部分需要这样做。
2)在侦听器中实现一个特定的回调方法而不是在单个方法中检查事件id常量是更清晰的设计。实际上,在过去,我们只会根据事件ID从单个事件回调方法委托私有方法。
3)这允许使用Adapter类,这些类有助于仅为感兴趣的事件实现回调方法。
答案 1 :(得分:0)
经过一番思考后,我认为我看到了双重编码事件子类型(示例中的Bar
,Baz
,Qux
)的额外优势,超出了其历史重要性:
每个事件子类型有一个回调方法允许更清晰的侦听器实现,因为不需要类似开关的语句来为每个子类型执行不同的操作。到目前为止,这在大多数事件处理代码中使用并且非常明显。
从实现角度来看,事件对象本身具有子类型ID(getId()
,可以将其重命名为getType()
非事件事件)本身相对来说成本相对较低(定义一堆常量并使它们与相应的子类型方法保持同步);并且当存在时允许有趣的调试策略:由特定模型触发的事件序列可以包含重建模型的所有更改所需的所有信息。从本质上讲,它使fooEvent.toString()
更加详细。
我进一步怀疑“完全自包含的事件对象允许更容易调试”是历史双重编码的一个强有力的原因。