场景:假设我有一个基类SketchbookEventObserver
和派生类MouseClickObserver
,TouchObserver
和TextChangedObserver
。
所有这些SketchbookEventObserver
都必须向网络请求有关发生的事件的数据:
MouseClickObserver
-鼠标单击的坐标。
TouchObserver
-触摸的坐标和持续时间。
TextChangedObserver
-具有文本框标识符的旧文本和新文本。
所有这些观察者都注册在UIEventRegistry
类上。事件发生时,它将在每个观察者上调用OnEvent
,并作为参数传递:
但是,我无法在每个派生类中使用不同的输入参数覆盖OnEvent
。如果我有通用和多态的输入参数,例如使用EventData
函数说GetData()
,我仍然需要在GetData()
的派生类中覆盖EventData
返回值。这也是不可能的。
另一个选择是在这些观察者之间没有任何继承,并将它们视为独立的实体。 EventRegistry
将具有每种类型的观察者的数组/列表,其中已知其类型,然后针对鼠标单击事件调用mMouseClickObservers[i].OnEvent()
,对于触摸事件调用mTouchObservers[i].OnEvent()
,依此类推。
但这意味着EventRegistry
将需要具有有关具体类的知识,如果EventRegistry
是不同库/包的一部分,则需要公开公开这些具体类。
有没有更好的方法来设计这个?
答案 0 :(得分:1)
一种方法是可以从EventData类派生MouseClickEventData,TouchEventData,TextChanged类。并强制转换EventData,以便为每个数据提供特定的类。
OnEvent(EventData *data) {
if (data->type == MOUSE_CLICK) {
MouseClickEventData *mData = dynamic_cast<MouseClickEventData*>(data);
// use mData->getCoordinates();
}
if (data->type == TEXT_CHANGED) {
TextChangedEventData *tData = dynamic_cast<TextChangedEventData*>(data);
// use tData->getNewText();
}
....
}
答案 1 :(得分:1)
为了基于观察者的类型和被观察的事物来改变观察者的行为,我们需要使用double-dispatch。 Visitor Pattern使用双调度来允许一组访问者观察一组事件。我在这里不提供实现,但是伪代码类似于:
interface SketchbookEventObserver:
void handle(MouseClickEvent event);
void handle(TouchEvent event);
interface SketchbookEvent:
void accept(SketchbookEventObserver observer);
class MouseClickObserver implements SketchbookEventObserver:
void handle(MouseClickEvent event):
...
void handle(TouchEvent event):
...
interface MouseClickEvent implements SketchbookEvent:
void accept(SketchbookEventObserver observer):
observer.handle(this);
另一种方法是为每种类型的事件注册一个侦听器。这是Java及其UI框架采用的方法。例如:
class Component:
void registerMouseClickListener(MouseClickListener listener):
...
void registerTouchListener(TouchListener listener):
...
interface MouseClickListener:
void handle(MouseClickEvent event);
interface TouchListener:
void handle(TouchEvent event);
答案 2 :(得分:1)
另一种选择是在这些观察者之间没有任何继承,并将它们视为单独的实体。
这是我最喜欢的选项,也是我多次提倡的选项,因为它可以维护事件的类型安全。如果每个事件都不相同,请不要通过相同的API来全部处理。
但这意味着
EventRegistry
将需要具有有关具体类的知识...
MouseClickObserver
,TouchObserver
和TextChangedObserver
应该都是抽象的。现在,每个抽象可能只有一个实现。但设计不应强制执行该操作。