views:

85

answers:

3

I have defined an Event class:

Event

and all the following classes inherit from Event:

SportEventType1 SportEventType2 SportEventType3 SportEventType4

Right now I will only have SportEvents but I don't know if in the future I'll want some other kind of events that doesn't even have anything to do with Sports.

Later, I will want to draw some graphics with info taken from Events, and the drawing logic can be a bit complex. But, for the moment, I think I shouldn't think of how the drawing will be done and I believe that maybe it'd be better if that drawing part was not put as an integral part of the Event/SportEventX class chain.

I am looking for solutions for this problem. I know I could just make Event have an instance variable(attribute, for the java crowds) pointing to something as an IDrawInterface, but that would make the Event class "assume" it will be later used for drawing. I would like to make the Event class oblivious to this if possible.

Thanks!

+3  A: 

Your intent to keep knowledge of the drawing process outside the Event class hierarchy is good.

A common way to handle this sort of thing in an OO language is the Visitor Pattern.

If you can't actually change the Event class to add the accept(Visitor v) needed for Visitor, you might consider using a Decorator or an Adapter. Getting the accept method to vary by subclass might be painful with these though. I'll think about this a bit more and maybe add further notes tonight. For now, I've got to get to work.

Don Roby
From what I'm reading now about the Visitor Pattern, that would mean I'd have to add a method to my Event class. What if that class wasn't mine/I couldn't change it anymore?
devoured elysium
In C#, you can use extension methods to add things to classes that aren't yours.
GWLlosa
Extension methods will *not* give you dynamic dispatch, though, so you can't implement the visitor pattern using them.
munificent
+1  A: 

One other solution might be to have an DrawbleEvent abstract class where different sportingevents can inherit from.

public abstract DrawableEvent
{
    Event event;
    IDrawingStrategy drawingstrategy;
    public Draw()
    {   
        drawingStrategy.Draw();
    }

}
public SportingEvent1 : DrawableEvent
{
    SprortingEvent1(Event event, IdrawingStrategy strategy)
    {
         this.event=event;
         this.drawingstrategy = strategy;
    }
}

The Event reference can go to the strategy or to the sprorting event depending on where it is needed.

derdo
From what I can see that would require that for each SportEvent I'd have one SportingEvent(that is Drawable), right? I had though of that, and in worse case scenario, i'll use that. Thanks
devoured elysium
Yes each SportingEvent inherits from DrawableEvent. DrawingStrategy is kinda optional. if drawing behavior is the same for some sportingEvent it makes more sense.
derdo
+1  A: 

Here's a more complex but pretty flexible approach. We'll define an interface for a type that can draw some events:

interface IEventRenderer
{
    // Draw the given event, if it can. Return true if the event was drawn,
    // false otherwise.
    bool Draw(Event event);
}

It does two things: it checks to see if it can draw a given event, and, if so, draws it. Otherwise it bails and returns false.

For example, a class that can render Sport1Events looks like:

class Sport1EventRenderer : IEventRenderer
{
    public bool Draw(Event event)
    {
        var sportEvent = event as Sport1Event;

        // can only draw this type
        if (sportEvent == null) return false;

        // draw the event...

        return true;
    }
}

Then we'll define a registry class. It's job is to maintain a collection of these renderers and hand off the work of drawing an event to the appropriate one:

class EventRendererRegistry
{
    public void Add(IEventRenderer renderer)
    {
        mRenderers.Add(renderer);
    }

    public void Draw(Event event)
    {
        foreach (var renderer in mRenderers)
        {
            if (renderer.Draw(event)) break;
        }
    }

    private readonly List<IEventRenderer> mRenderers = new List<IEventRenderer>();
}

All it does is find the first renderer that can successfully draw the event. You would then use this like:

var registry = new EventRendererRegistry();
registry.Add(new Sport1EventRenderer());

registry.Draw(someEvent);

Pros:

  • Event types are not coupled to any rendering code.
  • Renderers are not coupled to each other.
  • Renderers are only coupled to the events they care about. (For example a Sport2EventRenderer would not need to be coupled to Sport1Event.)
  • Renders can do arbitrary logic to determine if they're appropriate. We're just doing a type test here, but we could see if the event implements a certain interface, has a certain property, is in a certain state, etc.
  • Relatively fast. No reflection beyond simple casting.

Cons:

  • Fairly complex.
  • Can fail at runtime to find a matching renderer.
  • Have to iterate through renderer collection each time to find a match.
munificent
About "Have to iterate through renderer collection each time to find a match." you can just use a Hashtable, which improves greatly performance.
devoured elysium
What would the keys be? As it stands, you can select a renderer by any arbitrary predicate function. You could pick a renderer by time of day if you wanted. Replacing that with a hashtable could be faster (depending on your key and how its generated) but also loses some dynamicism.
munificent
The class's type could the key, I'd say. Or not?
devoured elysium
That would limit you to only selecting a renderer based on event type. It would also not support event subtypes. (i.e. if a renderer can render events of type Base, you'd expect it to also allow Derived, but this wouldn't work that way.) Also, I'm not sure getting a class's hashcode is faster than just iterating through the colllection.
munificent