2010-04-06 2 views
1

Я определили класс событий:Добавление поведения к набору классов

Event 

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

SportEventType1 SportEventType2 SportEventType3 SportEventType4 

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

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

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

Спасибо!

ответ

3

Ваше намерение сохранить знание процесса рисования вне иерархии классов событий является хорошим.

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

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

+0

Из того, что я сейчас читаю о шаблоне посетителя, это означало бы, что я должен добавить метод в свой класс Event. Что, если этот класс не был моим/я больше не мог его изменить? –

+0

В C# вы можете использовать методы расширения, чтобы добавлять вещи к классам, которые не принадлежат вам. – GWLlosa

+0

Методы расширения * не * дают вам динамическую отправку, поэтому вы не можете реализовать шаблон посетителя, используя их. – munificent

1

Другим решением может быть абстрактный класс 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; 
    } 
} 

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

+0

Из чего я могу видеть, что для каждого SportEvent потребуется один SportingEvent (то есть Drawable), верно? У меня было хоть что-то, и в худшем случае я буду использовать это. Спасибо –

+0

Да каждый SportingEvent наследует от DrawableEvent. DrawingStrategy является необязательным. если поведение рисунка одинаково для некоторого sportingEvent, это имеет больше смысла. – derdo

1

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

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

Pros:

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

Минусы:

  • довольно сложным.
  • Может не работать во время выполнения, чтобы найти соответствующий рендерер.
  • Нужно перебирать визуализатор каждый раз, чтобы найти матч.
+0

О себе: «Нужно перебирать визуализацию каждый раз, чтобы найти совпадение». вы можете просто использовать Hashtable, что значительно повышает производительность. –

+0

Какими будут ключи? Как бы то ни было, вы можете выбрать средство визуализации любой произвольной функцией предиката. Вы могли бы выбрать рендер по времени, если хотите. Замена этого с помощью хэш-таблицы может быть быстрее (в зависимости от вашего ключа и способа его создания), но также и теряет динамизм. – munificent

+0

Тип класса мог бы сказать ключ, я бы сказал. Или нет? –

Смежные вопросы