处理多种消息types的devise模式

我已经把GOF坐在了我的桌子上,我知道必须有某种devise模式来解决我遇到的问题,但是我无法解决这个问题。

为了简单起见,我改变了我使用的一些接口的名字。

所以这里的问题,在电线的一侧,我有多个服务器发送不同types的消息。 另一方面,我有一个客户端,需要能够处理所有不同types的消息。

所有消息实现相同的通用接口IMessage。 我的问题是,当客户端得到一个新的IMessage,它是如何知道它收到的IMessagetypes?

我想我可以做下面的事情,但这只是感觉糟糕。

TradeMessage tMessage = newMessage as TradeMessage; if (tMessage != null) { ProcessTradeMessage(tMessage); } OrderMessage oMessage = newMessage as OrderMessage; if (oMessage != null) { ProcessOrderMessage(oMessage); } 

第二个想法是将一个属性添加到名为MessageTypeID的IMessage中,但是这需要我写下如下内容,这也是FEEL可怕的。

 TradeMessage tMessage = new TradeMessage(); if (newMessage.MessageTypeID == tMessage.MessageTypeID) { tMessage = newMessage as TradeMessage; ProcessTradeMessage(tMessage); } OrderMessage oMessage = new OrderMessage(); if (newMessage.MessageTypeID == oMessage.MessageTypeID) { oMessage = newMessage as OrderMessage; ProcessOrderMessage(oMessage); } 

我知道这个普遍的问题已经被解决了一百万次,所以必须有一个更好的方法来解决以接口为参数的方法的问题,但是基于什么类实现了这个接口需要不同的stream量控制。

您可以为每个消息types创build单独的消息处理程序,然后将消息传递给每个可用的处理程序,直到find能处理它的程序。 类似于责任链模式:

 public interface IMessageHandler { bool HandleMessage( IMessage msg ); } public class OrderMessageHandler { bool HandleMessage( IMessage msg ) { if ( !msg is OrderMessage) return false; // Handle the message. } } public class SomeOtherMessageHandler { bool HandleMessage( IMessage msg ) { if ( !msg is SomeOtherMessage ) return false; // Handle the message. } } ... 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. } } } 

您也可以将其实现为一个映射,将消息类名称或消息types标识作为键,并将适当的处理程序实例作为值。

其他人则build议让消息对象自己“处理”,但这对我来说并不合适。 似乎最好是将消息的处理与消息本身分开。

还有一些我喜欢的东西:

  1. 你可以通过spring或者what-have-you来注入消息处理程序,而不是在构造函数中创build它们,这使得它非常容易testing。

  2. 您可以通过简单地从ProcessMessage循环中删除“break”来引入类似单个消息的多个处理程序的类似于主题的行为。

  3. 通过将消息从处理程序中分离出来,可以为不同的目标处理同一消息的不同处理程序(例如,多个处理相同消息的MessageProcessor类)

一些解决scheme适用于此,首先是最好的解决scheme,最后是最不好的。 所有的例子都是伪代码:

第一,也是最好的解决scheme

Vincent Ramdhanie介绍了实际的正确模式来解决这个问题,这就是所谓的战略模式 。

这种模式创build一个单独的“处理器”,在这种情况下相应地处理消息。

但是我很确定在GOF的书中给出了一个很好的解释:)

第2

正如所评论的,消息可能无法自行处理,为消息或基类创build接口仍然有用,因此您可以为消息创build一个通用的处理函数,并将其重载为更具体的消息。

在任何情况下,重载都会更好,然后为每种types的消息创build一个不同的方法。

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

第3

如果你的消息可以自己处理,你可以编写一个接口,因为你的处理方法取决于你得到的消息,似乎更容易把它放在消息类中。

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

然后在所有的消息类中实现它,并处理它们:

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

在你的列表中你可以存储任何实现这个接口的类。

从我的消息处理经验来看,消息的不同消费者通常需要处理各种消息types。 我发现Double Dispatch模式很好地处理这个问题。 其基本思想是注册一组处理程序,根据特定types(使用函数重载)将接收到的消息分派给处理程序进行处理。 消费者只注册他们希望接收的特定types。 下面是一个类图。

双调度UML类图

代码如下所示:

IHandler

 public interface IHandler { } 

IMessageHandler

 public interface IMessageHandler<MessageType> : IHandler { void ProcessMessage(MessageType message); } 

即时聊天

 public interface IMessage { void Dispatch(IHandler handler); } 

MessageBase

 public class MessageBase<MessageType> : IMessage where MessageType : class, IMessage { public void Dispatch(IHandler handler) { MessageType msg_as_msg_type = this as MessageType; if (msg_as_msg_type != null) { DynamicDispatch(handler, msg_as_msg_type); } } protected void DynamicDispatch(IHandler handler, MessageType self) { IMessageHandler<MessageType> handlerTarget = handler as IMessageHandler<MessageType>; if (handlerTarget != null) { handlerTarget.ProcessMessage(self); } } } 

DerivedMessageHandlerOne

 // Consumer of DerivedMessageOne and DerivedMessageTwo // (some task or process that wants to receive messages) public class DerivedMessageHandlerOne : IMessageHandler<DerivedMessageOne>, IMessageHandler<DerivedMessageTwo> // Just add handlers here to process incoming messages { public DerivedMessageHandlerOne() { } #region IMessageHandler<MessaegType> Members // ************ handle both messages *************** // public void ProcessMessage(DerivedMessageOne message) { // Received Message one, do something with it } public void ProcessMessage(DerivedMessageTwo message) { // Received Message two, do something with it } #endregion } 

DerivedMessageOne

 public class DerivedMessageOne : MessageBase<DerivedMessageOne> { public int MessageOneField; public DerivedMessageOne() { } } 

那么你只需要一个容器来pipe理处理程序,而且你已经完成了设置。 收到消息时,处理程序列表中的一个简单的循环,处理程序在他们想要的地方接收消息

 // Receive some message and dispatch it to listeners IMessage message_received = ... foreach(IHandler handler in mListOfRegisteredHandlers) { message_received.Dispatch(handler); } 

这个devise出现了一个问题,我问了一下关于Polymorphic Event Handling的问题

一个select是让消息自己处理。 也就是说,创build一个名为IMessageProcessor的接口,它指定了一个方法processMessage(IMessage)。 接下来定义为每种消息types实现IMessageProcessor的具体类。

每个IMessage类将定义它自己的处理器。

当你接收到一个消息对象时,你将会这样做:

 message.processor.processMessage(); 

对于我的Silverlight应用程序中的小型消息框架,我使用了Mediator模式。 这是某种消息总线/代理,对象正在为其订阅特定types或types的消息。 那么这个调解对象(经纪人/公共汽车)正在决定谁将收到什么样的消息。
有点像:

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

所调用的示例方法:

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

或发布(广播)消息:

 Publish(new ChatMessage()); 

BaseMessage是抽象类,我所有的消息都是inheritance的,并且只是引用发送者和一些独特的Guid。

我从MVVM Light Toolkit开始构build我的消息框架的起点,你可以看看他们的源代码,这并不复杂!

如果你想,我可以把C#代码放在这个地方?

您可能想要通过Gregor Hohpe和Bobby Woolf的“ 企业集成模式”来看看。 它有一个好的消息处理模式目录。

调度模式可能运作良好。

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

这个主题有各种各样的变化。 他们都将有一个调度对象,其中包含许多不同的处理程序。 如果调度程序找不到特定的处理程序,则应该考虑默认处理程序。 如何select将消息分发给相应的处理程序有很大的自由度。 我只是发生基于types,但你可以使它任意更复杂。 也许调度员可以检查消息的内容以发现最佳处理程序。 也许这个消息带有一个标识首选处理程序的键。 我不知道。 这里有很多的可能性。

将一个ProcessMessage()方法添加到iMessage接口,并让具体消息多态地决定正确的方式来处理它们自己。

你的代码就变成了

 newMessage.ProcessMessage(); 

这是一篇关于使用多态而不是条件的好文章。

在类似的情况下,我有一个服务器,从多个客户端接收大量不同的消息。

所有消息都被序列化,并以消息types的标识符开始。 然后我有一个switch语句看标识符。 消息然后被反序列化(对不同的对象)并进行适当的处​​理。

类似的事情可以通过传递实现包含指示消息types的接口的对象来完成。

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