Добавление поведения в набор классов - PullRequest
1 голос
/ 06 апреля 2010

Я определил класс события:

Event

и все следующие классы наследуются от Event:

SportEventType1 SportEventType2 SportEventType3 SportEventType4

Прямо сейчас у меня будут только SportEvents, но я не знаю, захочу ли я в будущем каких-то других событий, которые даже не имеют никакого отношения к спорту.

Позже я захочу нарисовать графику с информацией, взятой из Events, и логика рисования может быть немного сложной. Но на данный момент я думаю, что не должен думать о том, как будет выполняться рисование, и я считаю, что, возможно, было бы лучше, если бы эта часть рисунка не была включена в качестве неотъемлемой части цепочки классов Event / SportEventX.

Я ищу решение этой проблемы. Я знаю, что мог бы просто заставить Event иметь переменную экземпляра (атрибут для толпы Java), указывающую на что-то как IDrawInterface, но это заставило бы класс Event «предполагать», что он будет позже использован для рисования. Я хотел бы, чтобы класс Event не обращал на это внимания, если это возможно.

Спасибо!

Ответы [ 3 ]

3 голосов
/ 06 апреля 2010

Ваше намерение сохранить знание процесса рисования вне иерархии классов Event - это хорошо.

Распространенным способом обработки такого рода вещей на языке ОО является Шаблон посетителя .

Если вы на самом деле не можете изменить класс Event для добавления accept(Visitor v), необходимого для посетителя, вы можете рассмотреть возможность использования Decorator или Adapter . Однако заставить метод accept варьироваться в зависимости от подкласса может быть болезненно. Я подумаю об этом немного больше и, возможно, добавлю еще заметки сегодня вечером. На данный момент я должен приступить к работе.

1 голос
/ 06 апреля 2010

Вот более сложный, но довольно гибкий подход.Мы определим интерфейс для типа, который может рисовать некоторые события:

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

Он делает две вещи: он проверяет, может ли он нарисовать данное событие, и, если так, рисует его.В противном случае он возвращает значение false.

Например, класс, который может отображать Sport1Events, выглядит следующим образом:

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;
    }
}

Затем мы определим класс реестра.Его работа состоит в том, чтобы поддерживать коллекцию этих средств визуализации и передавать работу по рисованию события соответствующему:

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>();
}

Все, что он делает - это находит первого средства визуализации, которое может успешно нарисовать событие.Затем вы должны использовать это как:

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

registry.Draw(someEvent);

Плюсы:

  • Типы событий не связаны с каким-либо кодом рендеринга.
  • Средства визуализациине связаны друг с другом.
  • Средства визуализации связаны только с событиями, которые им небезразличны.(Например, Sport2EventRenderer не нужно связывать с Sport1Event.)
  • Рендеры могут выполнять произвольную логику, чтобы определить, являются ли они подходящими.Мы просто проводим здесь тестирование типа, но мы могли видеть, реализует ли событие определенный интерфейс, имеет ли определенное свойство, находится в определенном состоянии и т. Д.
  • Относительно быстро.Никаких отражений, кроме простого приведения.

Минусы:

  • Довольно сложный.
  • Может произойти сбой во время выполнения, чтобы найти подходящий рендерер.
  • При каждом совпадении приходится перебирать коллекцию рендерера.
1 голос
/ 06 апреля 2010

Еще одним решением может быть наличие абстрактного класса DrawbleEvent, от которого могут наследоваться различные спортивные события.

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;
    }
}

Ссылка на Событие может перейти к стратегии или спортивному событию в зависимости от того, где это необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...