代码之家  ›  专栏  ›  技术社区  ›  Assaf Neufeld

多个方法的正确C#设计模式是什么,它们都接受不同的派生类作为参数?

  •  2
  • Assaf Neufeld  · 技术社区  · 15 年前

    我有一个基本类:

    class Message
    

    和两个派生类:

    class SimpleMessage : Message
    class ComplexMesssage : Message
    

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

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

    一种选择是使用策略模式进行封装(至少在我的理解中是这样):

    class ProcessableMessage
    {
    delegate void ProcessMessageDelegate(Message m)
    
    private Message m;
    private ProcessMessageDelegate ProcessMessage;
    }
    

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

    还有更好的解决方案吗?

    谢谢
    阿萨夫

    3 回复  |  直到 15 年前
        1
  •  4
  •   Tim Robinson    15 年前

    我在这里使用访客模式:

    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);
        }
    }
    
        2
  •  3
  •   Merlyn Morgan-Graham    15 年前

    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()
        {
            // ...
        }
    }
    

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

        3
  •  0
  •   Just another metaprogrammer    15 年前

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

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

    这个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/