3

I am trying to write a generic Event System. For this i'd like to create an Interface for the EventHandler like this*(which not works)*:

public interface GameEventHandler<I extends GameEvent<TYPE extends Enum<?>, ATT extends Enum<?>>> {
    public void handleEvent(final GameEvent<TYPE, ATT>... e);
    public void registerListener(final GameEventListener<I> listener,
            final TYPE... type);
    public void unregisterListener(final GameEventListener<I>... listener);
    public void unregisterAllListener();
    public void unregisterAllListener(final I... type);
    public void processEvents();
    public void processEvents(final int maxTimeInMS);
}

but this does not work as i "think" it.

The Event itself is a Generic Element which is preaty simple this:

public class GameEvent<T extends Enum<?>, S extends Enum<?>> {
    private HashMap<S, String> values;
    private T type;

    public void init(T type) {
        this.type = type;
    }

    public T getType() {
        return this.type;
    }

    public void addMessage(S t, String value) {
        this.values.put(t, value);
    }

    public void getMessage(S t) {
        this.values.get(t);
    }
}

if i implement the HandlerInterface id like to have it still generic so there is something like a DefaultHandler<GameEvent<TypeEnum, AttributEnum>>() to init it. So you can use the Interface to create your own handler or use the DefaultHandler which i provide but still can use your own Enums.

At the moment i were able to create the interface like this:

public interface GameEventHandler<I extends GameEvent<TYPE, ATT>, TYPE extends Enum<?>, ATT extends Enum<?>> 

But i dont get the Implementation of an DefaultHandler Generic

public class DefaultGameEventHandler implements GameEventHandler<GameEvent<EventTypes, AttributeTypes>, EventTypes, AttributeTypes>  // not generic those are testing Enums

So what do i do wrong? Is it possible like i would like to have it?

Luigi
  • 4,129
  • 6
  • 37
  • 57
bemeyer
  • 6,154
  • 4
  • 36
  • 86

2 Answers2

1

To be honest, I'm not sure if I entirely understand your requirements. But if you want to make your DefaultGameEventHandler as generic as possible, I would suggest the following approach:

Instead of having a GameEventHandler interface that accepts Enums as generic EventTypes and AttributeTypes, make the GameEventHandler interface accept an EventType interface and an AttributeType interface:

public interface GameEventHandler<I extends GameEvent<TYPE, ATT>, TYPE extends EventType, ATT extends  AttributeType> {

    public void handleEvent(final GameEvent<TYPE, ATT>... e);
    public void registerListener(final GameEventListener<I> listener, final TYPE... type);

    public void unregisterListener(final GameEventListener<I>... listener);

    public void unregisterAllListener();
    public void unregisterAllListener(final I... type);

    public void processEvents();
    public void processEvents(final int maxTimeInMS);

}

Here are the corresponding interfaces and the GameEvent class:

public interface EventType {
    // common functionality of EventTypes, if any
}

public interface AttributeType {
    // common functionality of AttributeTypes , if any
}

public class GameEvent<T extends EventType, S extends AttributeType> {
    private HashMap<S, String> values;
    private T type;

    public void init(T type) {
        this.type = type;
    }

    public T getType() {
        return this.type;
    }

    public void addMessage(S t, String value) {
        this.values.put(t, value);
    }

    public void getMessage(S t) {
        this.values.get(t);
    }
}

You can then create any number of Enums that implement these interfaces:

enum MyEventTypes implements EventType{TYPE_1,TYPE_2,TYPE_3}

enum MyAttributeTypes implements AttributeType{ATT_1,ATT_2,ATT_3}

If you absolutely need the interfaces to provide functionality from the Enum class, you can still specify this in the interface like so:

public interface EventType {
    Enum<?> asEnum();
}

enum MyEventTypes implements EventType{
    TYPE_1,TYPE_2,TYPE_3;
    @Override
    public Enum<?> asEnum() {return this;}
}

Now you can create a generic DefaultGameEventHandler class that implements the GameEventHandler interface:

public class DefaultGameEventHandler<I extends GameEvent<TYPE, ATT>, TYPE extends EventType, ATT extends  AttributeType> implements GameEventHandler<I, TYPE, ATT>{ 

    @Override
    public void handleEvent(GameEvent<TYPE, ATT>... e) {
        //...
    }
    @Override
    public void registerListener(GameEventListener<I> listener, TYPE... type) {
        //...
    }
    @Override
    public void unregisterListener(GameEventListener<I>... listener) {
        //...
    }
    @Override
    public void unregisterAllListener() {
        //...
    }
    @Override
    public void unregisterAllListener(I... type) {
        //...
    }
    @Override
    public void processEvents() {
        //...
    }
    @Override
    public void processEvents(int maxTimeInMS) {
        //...
    }
}

You may instantiate the DefaultGameEventHandler with enums

//MyEventTypes and MyAttributeTypes are enums implementing EventType respectively AttributeType
DefaultGameEventHandler<GameEvent<MyEventTypes, MyAttributeTypes>, MyEventTypes, MyAttributeTypes> handler = new DefaultGameEventHandler<>();
GameEvent<MyEventTypes, MyAttributeTypes> event = new GameEvent<>();
event.addMessage(MyAttributeTypes.ATT_1, "some Message");
event.init(MyEventTypes.TYPE_1);
handler.handleEvent(event);
switch (event.getType()) {
    case TYPE_1:
        System.out.println("TYPE_1");
        break;
    case TYPE_2:
        System.out.println("TYPE_2");
        break;
    case TYPE_3:
        System.out.println("TYPE_3");
        break;
    default:
        break;
}

or also with the interfaces or any classes implementing the interfaces:

DefaultGameEventHandler<GameEvent<EventType, AttributeType>, EventType, AttributeType> handler = new DefaultGameEventHandler<>();
GameEvent<EventType, AttributeType> event = new GameEvent<>();
event.addMessage(MyAttributeTypes.ATT_1, "some Message");
event.init(MyEventTypes.TYPE_1);
handler.handleEvent(event);
EventType type = event.getType();
// To switch on the type you could use the asEnum() method
// and cast the type to the corresponding enum if possible:
if (type.asEnum().getClass() == MyEventTypes.class) {
    MyEventTypes t = (MyEventTypes)type.asEnum();
    switch (t) {
        case TYPE_1:
            System.out.println("TYPE_1");
            break;
        case TYPE_2:
            System.out.println("TYPE_2");
            break;
        case TYPE_3:
            System.out.println("TYPE_3");
            break;
        default:
            break;
    }
}
// Or you could also directly switch on the name of the enum (not recommended!):
switch (type.asEnum().name()) {
    case "TYPE_1":
        System.out.println("TYPE_1");
        break;
    case "TYPE_2":
        System.out.println("TYPE_2");
        break;
    case "TYPE_3":
        System.out.println("TYPE_3");
        break;
    default:
        break;
}

EDIT - In reply to the comment from BennX:

I think, that it would be rather good just to define the Eventhandlers and GameEvents with 2 Enums. But i think its not possible just with enums as you already marked.

Actually I didn't want to indicate, that using Enums is no possible. You can entirely replace the interfaces in my examples with Enums, if you wish:

public class GameEvent<T extends Enum<?>, S extends Enum<?>>

public interface GameEventHandler<I extends GameEvent<TYPE, ATT>, TYPE extends Enum<?>, ATT extends  Enum<?>>

public class DefaultGameEventHandler<I extends GameEvent<TYPE, ATT>, TYPE extends Enum<?>, ATT extends  Enum<?>> implements GameEventHandler<I, TYPE, ATT>

But why force Enums on the end users of the GameEventHandler? If you do not need any common functionality in your EventType and AttributeType, then you could even go without any enums or interfaces at all and make GameEventHandler entirely generic:

public interface GameEventHandler<I extends GameEvent<TYPE, ATT>, TYPE, ATT>

public class GameEvent<T, S>

public class DefaultGameEventHandler<I extends GameEvent<TYPE, ATT>, TYPE, ATT> implements GameEventHandler<I, TYPE, ATT>

The example code I posted above, where one instantiates the DefaultGameEventHandler with Enums, will still work with this generic GameEventHandler. But instead of Enums, the user could also decide to use final Integers, final Strings, or any other Object for the event and attribute types.

Balder
  • 8,623
  • 4
  • 39
  • 61
  • I am trying to create interfaces that allow someone to create an `EventHandler` as he whishes but also provide a kind of guided way for it. (Those interfaces) Id like to provde a default handler that already creates a pushing of all events to the registered listeners when the process events is called. I think, that it would be rather good just to define the `Eventhandlers` and `GameEvents` with 2 `Enums`. But i think its not possible just with enums as you already marked. – bemeyer Feb 23 '14 at 14:33
  • @BennX I replied to your comment at the end of my answer. – Balder Feb 23 '14 at 19:32
  • You pointed out some really good things and it does work. Thanks for the help and thanks for that great answer! Maybe one more hint. How to get rid of Supprest warnings in the interfaces for example in this: `public void registerListener(final GameEventListener listener, final TYPE... type);`? – bemeyer Feb 24 '14 at 19:46
  • 1
    Generic variable argument parameters like `TYPE... type` cannot be guaranteed to be type safe by the compiler. See [here](http://stackoverflow.com/questions/12462079/potential-heap-pollution-via-varargs-parameter) and [here](http://www.angelikalanger.com/GenericsFAQ/FAQSections/ProgrammingIdioms.html#FAQ300). I you can yourself guarantee, that the method is type safe (e.g. if you are only reading from the passed in generic argument array and not writing to it), you can add an @SafeVarargs annotation to the method (you must then declare the method final), which will remove the warnings. – Balder Feb 25 '14 at 06:21
-1

I think you have to go with a DefaultGameEventHandler like:

class DefaultGameEventHandler<TYPE extends Enum<?>,ATT extends Enum<?>>  implements GameEventHandler<GameEvent<TYPE, ATT>,TYPE,ATT>
Salom
  • 16