2

我有一个基类:

class Message

和两个派生类:

class SimpleMessage : Message
class ComplexMesssage : Message

这些类型在代码的另一部分中使用,如下所示:

void ProcessSimpleMessage(SimpleMessage m)
void ProcessComplexMessage(ComplexMessage m)

这些方法不在 Message 类中,因为处理不是消息的一部分。

现在,我想避免使用 if/else/switch 结构,因为消息类型很多。在这里使用的最佳设计模式是什么?

一种选择是使用策略模式进行封装(至少据我了解):

class ProcessableMessage
{
delegate void ProcessMessageDelegate(Message m)

private Message m;
private ProcessMessageDelegate ProcessMessage;
}

但是,让所有处理方法都接受基本类型 Message 并在里面进行转换真的是最佳实践吗?另一个问题是消息的动态类型(简单或复杂)实际上存储在这个类的两个地方——消息和过程算法,这看起来有点难看。

有没有更好的解决方案?

谢谢!!
阿萨夫

4

3 回答 3

4

我会在这里使用访问者模式:

public interface IMessageVisitor
{
    void VisitSimple(SimpleMessage msg);
    void VisitComplex(ComplexMessage msg);
}

public abstract class Message
{
    public abstract void Accept(IMessageVisitor visitor);
}

public class SimpleMessage : Message
{
    public override void Accept(IMessageVisitor visitor)
    {
        visitor.VisitSimple(this);
    }
}

public class ComplexMessage : Message
{
    public override void Accept(IMessageVisitor visitor)
    {
        visitor.VisitComplex(this);
    }
}

public class MessageProcessor : IMessageVisitor
{
    void IMessageVisitor.VisitSimple(SimpleMessage msg)
    { process simple message }

    void IMessageVisitor.VisitComplex(ComplexMessage msg)
    { process complex message }

    public void Process(Message msg)
    {
        msg.Accept(this);
    }
}
于 2010-08-15T08:03:00.093 回答
3

为什么不只添加虚拟方法:

class Message
{
    public abstract void Process();
}

如果您确实需要将代码分开:

class Message
{
    public abstract void Process();
}

class SimpleMessage
{
    public override void Process()
    {
        new SimpleMessageProcessor().Process();
    }
}

class SimpleMessageProcessor
{
    internal void Process()
    {
        // ...
    }
}

我的意思是,我们需要什么样的灵活性?还涉及哪些其他类?你周围的场景是什么?没有任何其他上下文,这确实是最容易理解和最容易实现的方法。有时人们会在真正不需要的时候添加设计杂乱无章的东西。

策略模式通常适用于如果您希望使用不同的方法来处理相同的消息类型,并希望在运行时切换它们。如果一种类型的处理通常与一种类型的消息一起使用,那么您不需要让它变得更复杂。

于 2010-08-15T07:47:10.553 回答
0

我喜欢上面的访问者方法。然而,只是为了好玩,我展示了如何在 VS2008 和 VS2010 中使用 T4 减少代码冗余。

冗余来自您需要访问方法的每条消息。此外,每种方法都需要一个简单但冗余的 Accept 实现。接近“不要重复自己”的一种方法是使用 T4 生成代码。

为了测试以下示例,在 VS 中添加一个类,但将扩展名从 .cs 更改为 .tt。您现在将获得两个文件,一个 .tt 文件和一个连接到 .tt 文件的 .cs 文件。

.tt 文件是生成 .cs 文件的模板。当时它们是相同的。

将此用作 .tt 文件的内容:

<#@ template language="C#" #>
<#
   // On VS2008 change C# above to C#v3.5

   // -----------------------------------------------------
   // Here we declare our different message types
   var messageTypes = new []
      {
         "Simple",
         "Complex",
         "Other",
      };
   // -----------------------------------------------------
#>

namespace MessageProcessor
{
   partial interface IMessageVisitor
   {
<#
   // Let's generate all message visitor methods
   foreach (var messageType in messageTypes)
   {
#>
      void Visit (<#=messageType#>Message message);
<#
   }
#>
   }
   abstract partial class Message
   {      
      public abstract void Accept (IMessageVisitor visitor);
   }
<#
   // Let's generate all message types
   foreach (var messageType in messageTypes)
   {
#>
   sealed partial class <#=messageType#>Message : Message
   {      
      public override void Accept (IMessageVisitor visitor)
      {
         visitor.Visit (this);
      }
   }
<#
   }
#>
}

这应该会生成一个如下所示的 CS 文件:

namespace MessageProcessor
{
   partial interface IMessageVisitor
   {
      void Visit (SimpleMessage message);
      void Visit (ComplexMessage message);
      void Visit (OtherMessage message);
   }
   abstract partial class Message
   {      
      public abstract void Accept (IMessageVisitor visitor);
   }
   sealed partial class SimpleMessage : Message
   {      
      public override void Accept (IMessageVisitor visitor)
      {
         visitor.Visit (this);
      }
   }
   sealed partial class ComplexMessage : Message
   {      
      public override void Accept (IMessageVisitor visitor)
      {
         visitor.Visit (this);
      }
   }
   sealed partial class OtherMessage : Message
   {      
      public override void Accept (IMessageVisitor visitor)
      {
         visitor.Visit (this);
      }
   }
}

为什么这不那么冗余?因为现在每当我想添加新消息时,我只需将其添加到模板中:

   var messageTypes = new []
      {
         "Simple",
         "Complex",
         "Other",
         "YetAnotherOne",
      };

重要的是要注意所有消息都是部分生成的,因为我们需要不同的消息有效负载。这是在另一个文件中指定的,它可能如下所示:

   partial class SimpleMessage
   {
      public string Name;
   }

   partial class ComplexMessage
   {
      public XmlDocument Xml;
   }

对于那些喜欢 T4 声音的人,请查看此博客:http ://www.olegsych.com/2008/09/t4-tutorial-creatating-your-first-code-generator/

于 2010-08-15T08:53:24.347 回答