Шаблон проектирования для обработки нескольких типов сообщений

Если вы не хотите смешивать вывод с time и командой. С GNU-временем вы можете использовать -o file, например:

/usr/bin/time -o tim grep -e k /tmp 1>out 2>err

, а tim - время, out и err - stdout и stderr из grep.

30
задан bruno conde 25 September 2009 в 20:34
поделиться

8 ответов

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

public interface IMessageHandler {
    bool HandleMessage( IMessage msg );
}

public class OrderMessageHandler : IMessageHandler {
    bool HandleMessage( IMessage msg ) {
       if ( !(msg is OrderMessage)) return false;

       // Handle the message and return true to indicate it was handled
       return true; 
    }
}

public class SomeOtherMessageHandler : IMessageHandler {
    bool HandleMessage( IMessage msg ) {
       if ( !(msg is SomeOtherMessage) ) return false;

       // Handle the message and return true to indicate it was handled
       return true;
    }
}

... etc ...

public class MessageProcessor {
    private List<IMessageHandler> handlers;

    public MessageProcessor() {
       handlers = new List<IMessageHandler>();
       handlers.add(new SomeOtherMessageHandler());
       handlers.add(new OrderMessageHandler());
    }

    public void ProcessMessage( IMessage msg ) {
       bool messageWasHandled
       foreach( IMessageHandler handler in handlers ) {
           if ( handler.HandleMessage(msg) ) {
               messageWasHandled = true;
               break;
           }
       }

       if ( !messageWasHandled ) {
          // Do some default processing, throw error, whatever.
       }
    }
}

Вы также можете реализовать это как карту, с именем класса сообщения или идентификатором типа сообщения в качестве ключа и соответствующим экземпляром обработчика в качестве значения.

Другие предложили иметь сообщение объект "обрабатывает" сам по себе, но мне это кажется неправильным. Похоже, было бы лучше отделить обработку сообщения от самого сообщения.

Некоторые другие вещи, которые мне в нем нравятся:

  1. Вы можете внедрить обработчики сообщений через spring или что-то еще, а не создавать их в конструкторе, что делает его очень тестируемым.

  2. Вы можете ввести тематическое поведение, когда у вас есть несколько обработчиков для одного сообщения, просто удалив «разрыв» из цикла ProcessMessage.

  3. Отделив сообщение от обработчика, вы можете иметь разные обработчики для одного и того же сообщение в разных местах назначения (например, несколько классов MessageProcessor, которые по-разному обрабатывают одни и те же сообщения)

22
ответ дан 27 November 2019 в 18:14
поделиться

A couple of solutions are applicable for this, first is best solution, last is least best. All examples are pseudocode:

1st, and best solution

Vincent Ramdhanie introduced the actual correct pattern to solve this problem, which is called the strategy pattern.

This pattern creates a separate 'processor', in this case to process the messages accordingly.

But I'm pretty sure a good explanation is given in your book by the GOF :)

2nd

As commented, the message may not be able to process itself, it is still usefull to create an interface for the message, or a base class, so you can make a general processing function for a message, and overload it for more specific ones.

overloading is in any case better then creating a different method for every type of message...

public class Message {}
public class TradeMessage extends Message {}

public class MessageProcessor {
    public function process(Message msg) {
        //logic
    }

    public function process(TradeMessage msg) {
        //logic
    }
}

3rd

If your message could process itself you could write an interface, since your process method depends on what message you got, it seems easier to put it inside the message class...

public interface IMessage
{
    public function process(){}
}

you then implement this in all your message classes and proccess them:

list = List<IMessage>();
foreach (IMessage message in list) {
    message.process();
}

in your list you can store any class that implements that interface...

15
ответ дан 27 November 2019 в 18:14
поделиться

Для моего небольшого фреймворка обмена сообщениями внутри приложения Silverlight я использую шаблон посредника. Это своего рода шина / брокер обмена сообщениями, на которую объекты подписываются на определенный тип или типы сообщений. Затем этот объект-посредник (брокер / шина) решает, кто будет получать какие сообщения.
Что-то вроде:

SubscribeFor<ChatMessage>().If(x=>x.SomeProp==true).Deliver(MyMethod);

Примеры методов, которые вызываются:

void MyMethod(ChatMessage msg) , or
void MyMethod(BaseBessage msg)

или публикации (широковещательной рассылки) сообщений:

Publish(new ChatMessage());

BaseMessage - это абстрактный класс, который наследует все мои сообщения, и имеет только ссылку на отправителя и некоторый уникальный Guid.

Я взял за отправную точку для создания своей инфраструктуры обмена сообщениями MVVM Light Toolkit , вы можете взглянуть на их исходный код, это несложно!

Если хотите, я могу добавить код на C # для это где-нибудь?

3
ответ дан 27 November 2019 в 18:14
поделиться

Add a ProcessMessage() method to the iMessage interface and let the concrete message polymorphically decide the right way to process themselves.

Your code then becomes

newMessage.ProcessMessage();

Here is a good article on using polymorphism instead of conditionals.

2
ответ дан 27 November 2019 в 18:14
поделиться

Вы можете ознакомиться с Шаблоны интеграции предприятия Грегора Хопе и Бобби Вульфа. У него хороший каталог шаблонов для обработки сообщений.

2
ответ дан 27 November 2019 в 18:14
поделиться

В аналогичном сценарии у меня есть сервер, который получает множество разных сообщений от нескольких клиентов.

Все сообщения отправляются сериализованными и начинаются с идентификатора типа сообщения. Затем у меня есть оператор switch, смотрящий на идентификатор. Затем сообщения десериализуются (в очень разные объекты) и обрабатываются соответствующим образом.

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

public void ProcessMessage(IMessage msg)
{
    switch(msg.GetMsgType())  // GetMsgType() is defined in IMessage
    {
        case MessageTypes.Order:
            ProcessOrder(msg as OrderMessage);  // Or some other processing of order message
            break;
        case MessageTypes.Trade:
            ProcessTrade(msg as TradeMessage); //  Or some other processing of trade message
        break;
        ...
    }
}
1
ответ дан 27 November 2019 в 18:14
поделиться

Шаблон отправки может работать хорошо.

public static class MessageDispatcher
{
  private static readonly IMessageHandler s_DefaultHandler =
      new DefaultMessageHandler();
  private static readonly Dictionary<Type, IMessageHandler> s_Handlers =
      new Dictionary<Type, IMessageHandler>();

  static MessageDispatcher()
  {
    // Register a bunch of handlers.
    s_Handlers.Add(typeof(OrderMessage), new OrderMessageHandler());
    s_Handlers.Add(typeof(TradeMessage), new TradeMessageHandler());
  }

  public void Dispatch(IMessage msg)
  {
    Type key = msg.GetType();
    if (s_Handlers.ContainsKey(key))
    {
      // We found a specific handler! :)
      s_Handlers[key].Process(msg);
    }
    else
    {
      // We will have to resort to the default handler. :(
      s_DefaultHandler.Process(msg);
    }
  }
}

public interface IMessageHandler
{
  void Process(IMessage msg);
}

public class OrderMessageHandler : IMessageHandler
{
}

public class TradeMessageHandler : IMessageHandler
{
}

У этой темы есть всевозможные вариации. Все они будут иметь объект диспетчера, содержащий множество разных обработчиков. Вы должны рассмотреть обработчик по умолчанию, если диспетчер не может найти конкретный обработчик. Существует большая свобода в выборе способа отправки сообщений соответствующим обработчикам. Я просто отправляю по типу, но вы можете сделать это произвольно сложнее. Возможно, диспетчер сможет изучить содержимое сообщения, чтобы найти лучший обработчик. Возможно, сообщение содержит ключ, который определяет предпочтительный обработчик. Я не знаю. Здесь много возможностей.

2
ответ дан 27 November 2019 в 18:14
поделиться

One option is to have the messages come with their own handlers. That is, create an Interface called IMessageProcessor that specifies a method processMessage(IMessage). Next define concrete class that implements IMessageProcessor for each type of message.

Each IMessage class will then define its own Processor.

When you receieve a message object you will do something like this:

message.processor.processMessage();
4
ответ дан 27 November 2019 в 18:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: