我正在用Java编写一个库,它会根据类型抛出具有不同数据的不同类型的事件。
例如,这是扩展的EventObject:
public class FooEvent extends EventObject {
private final int eventType;
private final Object fooEventObject;
public FooEvent(int type, Object obj){/*...*/}
public int getEventType() {/*...*/}
public int getEventObject() {/*...*/}
}
以下是我的听众目前的样子:
FooEventListener listener = new FooEventListener() {
@Override
public void onDataChange(FooEvent event) {
switch(event.getEventType()) {
case EVENT_TYPE_BAR:
Bars bar = (Bars)event.getEventObject();
/*work with Bar object...*/
break;
case EVENT_TYPE_GOO:
Goo goo = (Goo)event.getEventObject();
/*work with Goo object...*/
break;
/* etc ...*/
}
}
}
我想知道这是否是解决这个问题的正确方法(虽然我怀疑它是,因为库的用户需要知道要转换的类型),其中我有不同的事件类型与对象和我不想去做一个不同的活动&每个人的倾听者。
答案 0 :(得分:3)
Guava的EventBus提供了一种稍微不同的方法,可以处理多种事件类型。
遗憾的是,没有简单的解决方案来拥有具有不同类型的类型安全事件系统。您需要为每种类型提供1个侦听器/发布实现,以便向一方讲述所有存在的事件类型。
有一种方法可以消除对instanceof
或switch (type)
的需求并进行投射:Visitor Pattern
模式使用事件对象知道自己的类型这一事实,这意味着它们可以调用正确的方法。缺点是你需要一个包含所有类型的监听器接口。
public class Test {
abstract static class EventObject {
protected abstract void deliver(EventListener listener);
}
static class AEvent extends EventObject {
@Override
protected void deliver(EventListener listener) {
listener.onAEvent(this);
}
}
static class BEvent extends EventObject {
@Override
protected void deliver(EventListener listener) {
listener.onBEvent(this);
}
}
interface EventListener {
void onAEvent(AEvent event);
void onBEvent(BEvent event);
// ...
}
private static final EventListener LISTENER = new EventListener() {
@Override
public void onBEvent(BEvent event) {
System.out.println("Got B Event! " + event);
}
@Override
public void onAEvent(AEvent event) {
System.out.println("Got A Event! " + event);
}
};
private static void notifyListeners(EventObject event) {
event.deliver(LISTENER);
}
public static void main(String[] args) {
notifyListeners(new AEvent());
notifyListeners(new BEvent());
}
}
答案 1 :(得分:1)
解决这个问题的更好方法是使用泛型。
public class FooEvent<T> extends EventObject {
private final T fooEventObject;
public FooEvent(T obj){/*...*/}
public T getEventObject() {/*...*/}
}
//usage
SomeType object = new SomeType();
new FooEvent<SomeType>(object);
答案 2 :(得分:0)
我认为这是一种可行的方式,但不是最干净的方式。你应该创建一个抽象类
public abstract class AbstractEventType<T> extends EventObject {}
并从那延伸:
public abstract class FooEvent extends AbstractEventType<Foo> {}
public abstract class BarEvent extends AbstractEventType<Bar> {}
然后,您需要触发不同的事件,并根据类型具有不同的事件侦听器:
public interface FooEventListener {
public void onFooChange(FooEvent fooEvent);
}
等
如果您只想坚持一种事件类型,那么您至少可以移动代码来确定框架的类型,并避免污染&#34;业务&#34;代码,通过为每种类型创建一个处理程序方法,例如
public interface MyEventListener {
public void onFooChange(EventType<Foo> eventType);
public void onBarChange(EventType<Bar> eventType);
}