views:

113

answers:

5

Let's say I have defined the following class:

public abstract class Event {
    public DateTime Time { get; protected set; }

    protected Event(DateTime time) {
        Time = time;
    }
}

What would you prefer between this:

public class AsleepEvent : Event {
    public AsleepEvent(DateTime time) : base(time) { }
}

public class AwakeEvent : Event {
    public AwakeEvent(DateTime time) : base(time) { }
}

and this:

public enum StateEventType {
    NowAwake,
    NowAsleep
}    

public class StateEvent : Event {
    protected StateEventType stateType;

    public StateEvent(DateTime time, StateEventType stateType) : base(time) {
        stateType = stateType;
    }
}

and why? I am generally more inclined to the first option, but I can't explain why. Is it totally the same or are any advantages in using one instead of the other? Maybe with the first method its easier to add more "states", altough in this case I am 100% sure I will only want two states: now awake, and now asleep (they signal the moments when one awakes and one falls asleep).

+6  A: 

I prefer the first. You can attach methods and behaviour to the classes, and move away from the switch/case pattern common with enums towards true polymorphism (and its benefits wrt. maintenance - adding new cases etc.).

Brian Agnew
+2  A: 

It depends on what you're doing. If you are only managing states, then I would say stick with Enums (It's what I would do). If your states are more than just states, if instances of them will have behaviours, then go with classes.

FrustratedWithFormsDesigner
Each state (Awake or Asleep) will have different behaviour.
devoured elysium
@devoured elysium: Ah, then they are more than simple states. If these "states" will be instatiated and "doing things", You're probably better off with a Class-based solution than an enum.
FrustratedWithFormsDesigner
+2  A: 

Definetly the first way. Requirments always change. Also it much, much more cleaner the first way - you can use the base type everywhere and thus not exposing any of the derived ones - polymorphism in it's finest.

Vladimir Georgiev
+3  A: 

Real OOPers don't use if! Prefer polymorphism to conditionals.

Of course there could be situations where the enum is the way to go (say, if you have a very, very large amount of states or you know that for the domain, it's very likely that all observers will be interested in all transitions), but in the general case, the first option is less complicated. Using the second approach, every listener must repeat the same piece of code:

if (theStateImInterestedIn == event.stateType){ 
    /* actual code */ 
}

And every listener needs this, except for the listeners which react in the same way to all transitions! Code duplication! Aaaaargh! As we all know, repeated code causes bugs (hence the DRY principle), and so we can conclude that your gut feeling is correct - the first option (using two different classes) is the better, as every individual listener implementation will have less boiler plate.

Also; add an else there and you've got interesting times ahead when you add a new state: Some listeners were interested in both types of events, and so assumed that the else branch meant "the state I didn't check for in the if". They now break because the else clause covers >1 state.

gustafc
+1  A: 

The disadvantage of the first one is you cannot change the state. If an object needs to go from awake state to asleep state you need to create a new object and copy the info etc. Shortly it won't work. Based on the names I think state changing behavior is needed this scenario.

Second option with enum will work but it will cause if/switch statements based on the state as other posters noted. The moment you repeat same type of switch/if statement (ifs are not the problem, the repeated ifs are the problem) it might be better to move to a polymorphic solution. In this case you would replace the enum with an interface or abstract class and have as many implementations as you want. The behavior that would go into the switch/if statements will go into methods in you concrete implementations

derdo
Forgot to tell this, I won't need to change the state after object creation.
devoured elysium
I got confused by the class names. I, myself, from occasionally change state from asleep to awake:). For no state change case, I also vote for the option 1 if there are repeated if statements based on the state.
derdo