Observer Pattern – Classes vs Enum for Events

observer-pattern

When building an Observer pattern, you need to define your events that the are broadcast and observed. Is it better to define an abstract Event class with multiple subclasses for each event, or to define a single enum, where each event is listed in the enum?

option 1:

public abstract class Event { }
public UserInputEvent extends Event {}
public NetwortkEvent extends Event{}

option 2:

public enum Event {
 USER_INPUT_EVENT,
 NETWORK_EVENT
}

I've seen examples of both:

I'm leaning towards option 2. A lot of my decision is based on the fact that I'm working in java, so this might be different for different languages:

  1. option 1 will require lots of if X instanceOf Y checks which looks ugly.
  2. option 2 will allow clean switch statements
  3. option 2 will list all possible events nicely in one location. I know most IDEs can show all subclasses of a class but this is less obvious.
  4. option 1 doesn't restrict the addition of more subclasses. If you are writing a library, any user of the library can subclass Event and clutter the code with more events. option 2 fixes the number of events until someone actually updates the enum
  5. option 1 allows for sub-sub events, which may be good or bad. (e.g. public TouchUserInputEvent extends UserInputEvent {}
  6. option 1 allows you to attach additional meta data to the event. IMO this can lead to cluttered code if your goal is simplicity.

as an example:

public UserInputEvent extends Event {
    int xLocation;
    int yLocation;
}

UPDATE:
I ended up going with option 1. I did have a need to include additional data in the event and using a class was the only way to go. Plush @whatsisname was right, having to re-fetch the updated event data would be callback hell.

Best Answer

My vote goes to option 1.

Because: there are no clean switch statements. When you have enums and start switching over them - you open the doors of a very dark place. First there is one switch, then there is another, and another, ...

And pretty soon, your code base has a lot of knowledge around the meaning of the different enum constants spread out in zillions of places.

There is only one good use for switches - which also "why option 1 is better". You see, in good OOP, you do not ask an object about its state to then make a decision on that. You rather invoke methods on that object and let it do what needs to be done.

In that sense: you spend your energy thinking up the common interface of your abstract class. And then you don't care about which "case" you have - because you always always always just invoke the same methods - but you do it on different objects.

And coming from there: sometimes you need to switch - because you have a factory that needs to find out what specific class needs to be instantiated and returned to the client code.

Long story short: the OOP answer to such kind of problems is polymorphism, and very often: a state machine. switch statements on the other hand have no(t much) place in OOP. The point is: using polymorphism, you can write code that is easier to maintain and enhance. Because such code nicely supports the open/closed principle. Scattered switch statements do not. To the contrary: they often force you to modify code when you try to enhance functionality.

[ for the record: I am not talking about fancy pattern matching as possible in newer languages - that would be a separate discussion ]

Related Topic