在C#中实现具有“条形”子集的“食物”集

时间:2013-04-23 13:41:24

标签: c# oop casting object-oriented-analysis

我正在编写一个服务器来处理从客户端到主机的不同类型的消息。消息具有不同的内容和长度,并且将在标识符前面标识消息的类型。某些消息(例如,类型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方式是什么,其中这些类型的子集是子类型?

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

5 个答案:

答案 0 :(得分:2)

这是一个包装内容的想法,以便您可以将它们传递给其他人。您可以定义MessageType以包装整个消息加载和标识,PayloadType包装所有类型的有效负载和子类 - ForwardMessage,ArchiveMessage - 以标识不同类型的有效负载。

  • 消息负责获取原始流输入

  • 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,
    }

答案 1 :(得分: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
            }
        }
    }
}

这个解决方案确实需要每个消息的对象实例,但在我看来它更优雅。

答案 2 :(得分: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;
    }
}

答案 3 :(得分: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);
}

答案 4 :(得分:0)

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

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

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

然后,只要有消息进入处理,您就可以创建该类型的实例。

var processor = MessageProcessorFactory.GetProcessor("TheTypeCodePrecedingTheData");
processor.Process(messageData);