Dondump
Dondump

Reputation: 39

Creating generic GWT Events: is this a good approach?

I'm trying to create a simple way to fire CRUD-type events for different domain classes. I've created the following event class:

public class EntityModifiedEvent<E> extends Event<EntityModifiedEventHandler<E>> {

private E element;
private ModType modType;
private Class<E> clazz;
private static Map<String,GwtEvent.Type<EntityModifiedEventHandler<?>>> types = new HashMap<String, GwtEvent.Type<EntityModifiedEventHandler<?>>>();

public EntityModifiedEvent(ModType modType, E element, Class<E> clazz) {
    this.element = element;
    this.modType = modType;
    this.clazz = clazz;
}

public Type<EntityModifiedEventHandler<?>> getType() {
    return getType(clazz);
}

@SuppressWarnings({"rawtypes", "unchecked"})
public static GwtEvent.Type<EntityModifiedEventHandler<?>> getType(Class clazz) {
    GwtEvent.Type type = types.get(clazz.toString());
    if (type == null) {
        type = new GwtEvent.Type<EntityModifiedEventHandler<?>>();
        types.put(clazz.toString(), type);
    }
    return type;
}

public E getElement(){
    return element;
}

public ModType getModType() {
    return modType;
}

@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Type<EntityModifiedEventHandler<E>> getAssociatedType() {
    return (Type) getType();
}

@Override
protected void dispatch(EntityModifiedEventHandler<E> handler) {
    handler.onEntityModified(this);
};

public interface EntityModifiedEventHandler<E> extends EventHandler {
    void onEntityModified(EntityModifiedEvent<E> entityModifiedEvent);
}

So, any class can register itself as a listener as follow:

getEventBus().addHandler(EntityModifiedEvent.getType(MyDomainClass.class), this);

And the events will be fired like:

getEventBus().fireEventFromSource(new EntityModifiedEvent<MyDomainClass>(ModType.CREATE, instanceModified, MyDomainClass.class), this);  

ModType is just a simple Enum with the different types of modifications. I have some concerns about having a map with all class.toString->eventTypes in this class itself. Do you think this will bring performance issues? Also, this approach relies on the EventBus using Type object's hashcode to identify the handlers registered for that type (see getType(Class clazz) function). Do you think it's wrong to rely on it?

Any other suggestion about how to do this? Any comment will be much appreciated!

Upvotes: 2

Views: 461

Answers (1)

Igor Klimer
Igor Klimer

Reputation: 15321

You have to ask yourself what do you gain from such an approach?

  • Performance - no. I don't have solid numbers on this (I'd have to be able to profile your application), but it's seems that this offers no measurable performance gains, if any. The number of fired events will be the same, but the number of receivers will be greater than with a more fine-grained approach. Plus, there's the type checking.
  • The ability to perform some common code when any entity modified event is fired, regardless of its type. This is true, but read on on how to achieve it with specific events.

Using specific events for the exact operation that was performed seems like a better choice:

  • It makes it clear who listens to what event.
  • The events can have extra metadata specific to the event (how many records where deleted, do you need to flush the cache, etc.)

I'd recommend looking at gwteventbinder to trim some of the boilerplate and improve your code. It also allows for handling several events in one method:

class SuperEvent extends GenericEvent { }

class EventOne extends SuperEvent { }

class EventTwo extends SuperEvent { }

class FormPresenter {
  interface MyEventBinder extends EventBinder<FormPresenter> {}
  private final MyEventBinder eventBinder = GWT.create(MyEventBinder.class);

  FormPresenter(EventBus eventBus) {
    eventBinder.bindEventHandlers(this, eventBus);
  }

  @EventHandler
  void onEventOne(EventOne event) {
    // handler for EventOne
  }

  @EventHandler(handles = {EventOne.class, EventTwo.class})
  void onEventOneAndTwo(SuperEvent event) {
    // handler for EventOne and EventTwo
  }

  @EventHandler(handles = {EventOne.class, EventTwo.class})
  void onEventOneAndTwo2() {
    // handler for EventOne and EventTwo without parameter
  }
}

Upvotes: 2

Related Questions