我正在编写一个服务器来处理从客户端到主机的不同类型的消息。消息具有不同的内容和长度,并且将在标识符前面标识消息的类型。某些消息(例如,类型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(标头是可转发的)。但遗憾的是,您不能从静态类继承。 。
答案 0 :(得分:2)
这是一个包装内容的想法,以便您可以将它们传递给其他人。您可以定义MessageType以包装整个消息加载和标识,PayloadType包装所有类型的有效负载和子类 - ForwardMessage,ArchiveMessage - 以标识不同类型的有效负载。
消息负责获取原始流输入
PayloadType负责加载其子类和常用
字段,包括MessageType
使用示例代码:
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);