Как обрабатывать различные обработки в зависимости от типа сообщения? - PullRequest
1 голос
/ 02 мая 2009

У меня есть процесс, у которого есть метод "уведомить", который получает в качестве параметра базовый класс типа сообщения. Я хотел бы сделать другую обработку в зависимости от производного типа сообщения. Означает ли это, что мне нужно добавить метод с именем «process» или что-то похожее на тип сообщения, и вызвать его с помощью полиморфизма? Лучше ли добавить «уведомление» для каждого конкретного типа сообщения?

Подробнее: язык C ++. Я подумал, что уведомление будет хорошей идеей, так что мне потребуется только один метод для уведомления о различных типах сообщений. Контроллер наследует от класса слушателя, который указывает метод чистого витального уведомления (MsgBaseClass). Мне все еще нравится эта идея, поскольку мне не нужно добавлять уведомления для каждого нового типа сообщения. Но в самом коде контроллера я не вижу никакого способа различить тип сообщения, отличный от типа динамического приведения или добавления типа сообщения к сообщению.

edit: Я думаю, что я собираюсь пойти с паттерном Visitor. Это позволяет мне сохранить только один метод для уведомления, и я могу избежать оператора switch в моем коде. Интерфейс «посетитель» будет указывать различные методы, необходимые слушателю для обработки различных производных типов сообщений. Для этого потребуется добавить только одно сообщение в базовый класс Message - чисто виртуальное «accept» (MyMessageTypeVisitor v). Производные классы сообщений будут реализовывать его с помощью v.visit (this);

Я думаю это достаточно.

Ответы [ 4 ]

1 голос
/ 02 мая 2009

Классический OO-ответ требует, чтобы базовый класс сообщений предоставлял абстрактный метод, который конкретные подклассы сообщений переопределяют для обеспечения конкретной обработки.

Некоторые (не очень распространенные) языки, такие как Dylan и CLisp, предоставляют «универсальные функции» (динамически отправляемые для типов аргументов), которые решают проблему довольно радикально.

Одним гибким подходом, доступным на популярных языках, является шаблон проектирования дяди Боба "Acyclic Visitor", http://www.objectmentor.com/resources/articles/acv.pdf; Дополнительные варианты для посетителей см. на сайте www.ccs.neu.edu/research/demeter/adaptive-patterns/visitor-usage/papers/plop96/variations-visitor-nordberg.ps.

1 голос
/ 02 мая 2009

Редактировать: я думаю, что у Dirkgently есть хороший момент, и что сообщения не должны знать, как обрабатывать себя. Поэтому описанный мной подход, при котором сообщения могут использоваться как фабрики, не очень хорошая идея. Я думаю, что абстрактная фабрика процессов может быть хорошим решением.

Используйте абстрактную фабрику для создания объекта, который может обрабатывать обработку, и вызывать его, используя полиморфизм. Эта фабрика может быть включена непосредственно в класс сообщений, или вы можете создать отдельный класс фабрики, который принимает тип сообщения в качестве параметра и возвращает соответствующий объект.

class Message {
public:
  virtual Processor *getProcessor() = 0;
  // other methods
};

class Processor {
public:
  virtual void doWork() = 0;
};

class MyListener : Listener {
public:
  void notify(Message *message);
};

void MyListener::notify(Message *message) {
  Processor *proc = message->getProcessor();
  proc->doWork();
};

(Извините, если это неверно. Мой C ++ немного слаб, но я считаю, что это иллюстрирует принцип.)

Это позволит вам просто переопределить getProcessor () для каждого типа сообщений и создать там соответствующий процессор.

IMVHO, Полиморфизм - это путь. Я предполагаю, что та логика обработки, которую вы хотите сделать, не относится к классу сообщений и должна быть перемещена в отдельные классы. Другая причина, по которой я бы предпочел этот подход, заключается в том, что он не требует от меня изменения структуры уведомляемого класса, если я добавляю дополнительные сообщения. Если существует только один или два типа сообщений, это может не быть проблемой.

0 голосов
/ 02 мая 2009

Вы можете сделать что-то вроде этого:

DerivedType *dt = dynamic_cast< DerivedType >( &BaseType );
if( dt != NULL )
{
    // Handle processing of DerivedType
}

Просто попробуйте сделать dynamic_cast для каждого обработанного DerivedType. Если вы получаете ненулевой указатель, то вы знаете, что получили тип, на который пытались привести.

0 голосов
/ 02 мая 2009

Вы застряли с шаблоном дизайна наблюдателя?

перегружен notify выглядит как кандидат. Шаблон наблюдателя действительно прост. Он основан на голливудском принципе , а именно: «Не звоните нам, мы вам позвоним!». Идея состоит в том, чтобы иметь набор объектов (наблюдателей) и уведомлять их, а не запрашивать у вас. Вы передаете типичные Event данные наблюдателям. Надо оставить наблюдателю решить, что с этим делать. Было бы немного dynamic_casts, если бы наблюдатели реагировали на разные события (да, вам нужна и иерархия событий).

...