3

我正在编写一个服务器来处理从客户端到主机的不同类型的消息。消息具有不同的内容和长度,并且将在前面有一个标识符,以标识消息的类型。一些消息(例如类型 A、B 和 C)应该只在机器之间转发。其他(例如 D、E 和 F 类型)需要来自服务器的特定操作:即。他们不只是转发。

(注意:两端的客户端需要区分 A、B 和 C,但服务器只需要知道转发这些消息。服务器和客户端都需要能够区分 D、E 和 F。 )

我试图找到的是一个很好的面向对象范式,用于表示消息是什么“类型”的概念。因此,为了澄清,假设服务器接收到标记为“B 型”的消息,它需要简单地将其转发给适当的客户端。但是,如果它收到标记为“F 型”的消息,它将采取不同的、具体的行动。那么我怎么能在我的代码中表示“类型”呢?

我想要实现的理想解决方案是这样的;和枚举“类型”,其中命令的某个子集属于“可转发”类型。显然这是不可能的,所以我想到了一个静态类 Forwardable,它继承自静态基类 Type。再次,不可能。接口是可能的,但我真的宁愿不必为了解释类型而实例化实例。

让服务器解析消息的最直接的方式是这样的:

byte[] payload = GetPayload((byte[])rawMessage);
Type message = GetMessageType((byte[])rawMessage);
if(message is Forwardable)
{
  ForwardMessage(payload);
}
else
{
  switch(message)
   case 1:
     //
     break;
   case 2:
     //
     break;
}

最后,什么是表示一组类型的正确 OO 方式,其中这些类型的子集是子类型?

编辑:在某种程度上,我觉得这应该通过定义一个“类型”的静态类并定义另一个从“类型”继承的名为“Forwardable”的静态类来完成。然后我可以将我的服务器接收到的内容转换为“类型”并说 if(header is Forwardable)。但不幸的是,您不能从静态类继承。. .

4

5 回答 5

2

这是一个将事情包装起来的想法,以便您可以将它们传递给其他人。您可以定义一个 MessageType 来包装整个消息的加载和识别,PayloadType 来包装各种有效负载和子类 - ForwardMessage、ArchiveMessage - 来识别不同类型的有效负载。

  • Message 负责获取您的原始流输入,

  • PayloadType 负责加载其子类和公共
    字段,包括 MessageType

  • ForwardMessage、ArchiveMessage 负责任何业务逻辑,它们不必知道从流中加载自身的任何事情。为不同类型的有效负载实施更多这些。

使用示例代码:

Message msg = Message.FromStream(stream);
PayloadType payload = msg.GetPayload();
payload.Process();

这是示例代码:

public class Message{
      public int Prefix {get; private set;}
      public byte[] RawPayload {get;private set;}

      public PayloadType GetPayload(){
        PayloadType result = null;
        switch (Prefix){ // you can also convert that to enum and use "if" for more complicated identification
          case 1: 
            result = PayloadType.FromRaw<ForwardMessage>(RawPayload);
            break;
          case 2: 
            result = PayloadType.FromRaw<ArchiveMessage>(RawPayload);
            break;
          default:
            break;
        }
      }

      public static Message FromStream(Stream s){
        Prefix = ReadTwoBytes(s);
        RawPayload = ReadToEnd(s);
      }
    }

    public abstract class PayloadType{
      public abstract MessageType MessageType {get;} // enum goes better here
      public abstract Process();

      public static T FromRaw(byte[] raw) where T: PayloadType{
        // deserialize this as you wish
        // such as:
        using (MemoryStream s = new MemoryStream(raw)){
          XmlSerializer xser = new XmlSerializer(typeof(T));
          return xser.Deserialize(s) as T; 
        }
      }
    }

    public ForwardMessage : PayloadType{
      public override MessageType MessageType {return MessageType.Forward;}
      public override Process(){
          // send this message elsewhere
      }
    }

    public ArchiveMessage: PayloadType{
      public override MessageType MessageType {return MessageType.Archive;}
      public override Process(){
           // store this message somehow
      }
    }

    public enum MessageType{
        Unknown, Formward, Archive,
    }
于 2013-04-23T14:10:27.500 回答
1

考虑到您的问题,我将执行以下操作:

  • 对每条消息使用对象表示
  • 使用诸如责任链之类的模式来根据消息的类型来处理消息。

这种架构的优点是您可以分离每种消息类型的处理逻辑。这允许您快速扩展它(添加新的消息处理程序或新的消息类型),而不会影响系统的其余部分。此外,您可以使用多态性来允许单个处理程序处理多种消息类型(在您的情况下为 ForwardHandler)。

这是一个简单的实现示例。

首先,消息类型:

public abstract class BaseMessage { ... } // base class inherited by every message
public abstract class ForwardableMessage : BaseMessage { ... } // base class for message that should only be forwarded
public class MessageOfTypeA : BaseMessage { ... } // a message of type A (which is not forwardable)
public class MessageOfTypeB : ForwardableMessage { ... } // a message of type B (which is forwardable)
public class MessageOfTypeC : ForwardableMessage { ... } // a message of type C (which is forwardable)

(请注意,在这种情况下,使用可转发消息的接口可能会更灵活,我会对人们对此事的看法感兴趣)。

其次,定义您的处理程序:

public abstract class BaseMessageHandler {

    public abstract bool CanHandle(BaseMessage msgToHandle)
    public abstract void Handle(BaseMessage msgToHandle);

}

public class MessageForwarderHandler : BaseMessageHandler {

    public bool CanHandle(BaseMessage msgToHandle)
    {
        return msgToHandle is ForwardableMessage;
    }

    public void Handle(BaseMessage msgToHandle)
    {
        // do the forwarding logic here
    }

}

public class MessageOfTypeAHandler : BaseMessageHandler {

    public bool CanHandle(BaseMessage msgToHandle)
    {
        return msgToHandle is MessageOfTypeA;
    }

    public void Handle(BaseMessage msgToHandle)
    {
        // do the logic specific to messages of type A
    }

}

最后,您必须实现一个维护不同处理程序列表的对象。

public static class MessageHandlersProvider
{
    IEnumerable<MessageHandler> handlers = new List<MessageHandler>()
    {
        new MessageOfTypeAHandler(),
        new MessageForwarderHandler()
    }

    public static void HandleMessage(BaseMessage msg)
    {
        foreach (MessageHandler handler in handlers)
        {
            if (handler.CanHandle(msg))
            {
                handler.Handle(msg);
                // you may stop once you have found a handler that can handle or you might consider that multiple handlers can be applied to the same message
            }
        }
    }
}

这个解决方案确实需要为每条消息创建一个对象实例,但在我看来,它要优雅得多。

于 2013-04-23T17:08:03.767 回答
0
public abstract class MsgType
{
  public bool IsForwardable { get; }
}

public class A : MsgType
{
  public override bool IsForwardable
  {
    get { return true; }
  }
}

public class F : MsgType
{
  public override bool IsForwardable
  {
    get { return false; }
  }
}

或第二种解决方案:

public interface Forwardable
{ }

public class A : Forwardable
{ }

public class F
{ }

或第三种解决方案

byte[] payload = GetPayload((byte[])rawMessage);
Type message = GetMessageType((byte[])rawMessage);
if(IsForwardable((byte[])rawMessage))
{
  ForwardMessage(payload);
}
else
{
  TakeAppropriateAction(message, payload);
}
于 2013-04-23T14:28:41.623 回答
0

这行得通吗?

enum ActionType
{
    Forwardable, ....
}

class Message //could be abstract, then make classes A : Message, B: Message etc with appropriate fields
{
    private Byte[] payload;

    public ActionType CurrentActionType {get;private set;}

    public Message(byte[] rawmessage)
    {
        //parse message's header to determine ActionType
        //parse rest of message and save to payload or other variables in inherited classes
    }
}

Message msg = new Message((byte[])rawMessage);
switch(msg.CurrentActionType)
{
    case ActionType.Forwardable :
        ForwardMessage(msg); break;
    case...
    case...
}

编辑ShouldForward评论中讨论的功能:

private Boolean ShouldForward(Message msg)
{
    switch(msg.CurrentActionType)
    {
        case ActionType.A:
        case ActionType.B:
        case ActionType.C:
            return true;
        default:
            return false;
    }
}
于 2013-04-23T13:55:32.460 回答
0

如何为每种处理类型(转发、删除等)创建一个类,然后用自定义 .NET 属性装饰它们 + 实现已知接口

[MessageProcessor("TypeB")]
public class TypeBMessageProcessor : IMessageProcessor
{
  void IMessageProcessor.Process(byte[] message)
  {
     ....
  }
}

然后,您可以在应用程序启动时扫描您的程序集,找到用您的自定义 MessageProcessorAttribute 修饰的类,然后将类型存储在由属性上的“TypeB”参数键入的字典中......由某种 MessageProcessorFactory 类持有。

然后,您可以在消息进入处理时创建该类型的实例。

var processor = MessageProcessorFactory.GetProcessor("TheTypeCodePrecedingTheData");
processor.Process(messageData);
于 2013-04-23T17:03:01.987 回答