开发者

Adding behaviour to a set of classes

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 开发者_如何学JAVAdoesn'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!


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜