简体   繁体   English

具有不同类型和数据的事件

[英]Events with different types and data

I am writing a library in Java, which throws an event of different types with differing data depending on the type. 我正在用Java写一个库,该库根据类型抛出具有不同数据的不同类型的事件。

For example, here is the extended EventObject: 例如,这是扩展的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() {/*...*/}
}

And here is how I my listener currently looks like: 这是我的听众当前的样子:

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 ...*/
        }
    }
}

I would like to know if this is the right way of solving this problem (although I doubt it is, since the user of the library would need to know what type to cast to) wherein I have different event types with objects and I do not want to go and make a different event & listener for each one. 我想知道这是否是解决此问题的正确方法(尽管我怀疑是这样,因为库的用户需要知道要转换为哪种类型),其中我的对象具有不同的事件类型,而我没有想要为每个事件创建一个不同的事件和侦听器。

Guava's EventBus provides a slightly different approach that can handle multiple event types. 番石榴的EventBus提供了一种略有不同的方法,可以处理多种事件类型。

There is unfortunately no easy solution to have a type safe event system with different types. 不幸的是,没有一个简单的解决方案来拥有具有不同类型的类型安全事件系统。 You either have to have 1 listener / publishing implementation per type of you need to teach one side about all the event types that exist. 对于每种类型,您要么必须具有1个侦听器/发布实现,要么需要向一侧介绍所有存在的事件类型。

There is a way to remove the need for instanceof or switch (type) and casting though: the Visitor Pattern 有一种方法可以消除对instanceofswitch (type)和转换的需要: Visitor Pattern

The pattern uses the fact that event objects know their own type which means they can call the right method. 该模式使用以下事实:事件对象知道它们自己的类型,这意味着它们可以调用正确的方法。 The downside is that you need a listener interface that contains all the types. 缺点是您需要一个包含所有类型的侦听器接口。

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());
    }

}

A better way to solve this is with generics. 解决此问题的更好方法是使用泛型。

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);

I think it's a way to go, but not the cleanest way. 我认为这是一种方法,但不是最干净的方法。 You should create an abstract class 您应该创建一个抽象类

public abstract class AbstractEventType<T> extends EventObject {}

and extend from that: 并从中扩展:

public abstract class FooEvent extends AbstractEventType<Foo> {}

public abstract class BarEvent extends AbstractEventType<Bar> {}

Then you need to fire different events and also have different event listeners based on the type: 然后,您需要触发不同的事件,并且根据类型还需要具有不同的事件侦听器:

public interface FooEventListener {
    public void onFooChange(FooEvent fooEvent);
}

etc. 等等

If you want to stick with only one event type then you could at least move the code to determine the type to your framework and avoid pollution of the "business" code, by creating one handler method per type, eg 如果您只想使用一种事件类型,则可以通过为每种类型创建一个处理程序方法,例如至少将代码移动到框架中以确定该类型,并避免污染“业务”代码。

public interface MyEventListener {
    public void onFooChange(EventType<Foo> eventType);
    public void onBarChange(EventType<Bar> eventType);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM