2

私は基本クラスを持っています:

class Message

および 2 つの派生クラス:

class SimpleMessage : Message
class ComplexMesssage : Message

これらの型は、コードの別の部分で次のように使用されます。

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

処理はメッセージの一部ではないため、これらのメソッドはクラス Message 内にはありません。

ここで、メッセージの種類が多いため、if/else/switch 構造は避けたいと思います。ここで使用するのに最適な設計パターンは何ですか?

1つのオプションは、戦略パターンを使用してカプセル化することです(少なくとも私が理解しているように):

class ProcessableMessage
{
delegate void ProcessMessageDelegate(Message m)

private Message m;
private ProcessMessageDelegate ProcessMessage;
}

しかし、すべての処理メソッドが基本型 Message を受け入れ、内部でキャストすることは本当にベスト プラクティスでしょうか? もう 1 つの問題は、メッセージの動的タイプ (単純または複雑) が実際にはこのクラスの 2 つの場所 (メッセージとプロセス アルゴリズム) に格納されていることです。

より良い解決策はありますか?

ありがとう!!
アサフ

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

つまり、ここではどのような柔軟性が必要なのでしょうか? 他にどのようなクラスが関係していますか? あなたの周囲のシナリオは何ですか?他のコンテキストがなければ、これは実際に理解するのが最も簡単で、実装するのが最も簡単な方法です。本当に必要のないときに、デザインのクラフトを追加することがあります。

通常、戦略パターンは、同じメッセージ タイプを処理するさまざまなメソッドが必要で、実行時にそれらを切り替えたい場合に使用します。1 つのタイプの処理が 1 つのタイプのメッセージに一般的に適用される場合は、これ以上複雑にする必要はありません。

于 2010-08-15T07:47:10.553 に答える
0

上記のVisitorアプローチが好きです。ただし、楽しみのために、VS2008およびVS2010でT4を使用してコードの冗長性を減らす方法について少し説明します。

冗長性は、Visitメソッドが必要な各メッセージに由来します。また、各メソッドには、Acceptの単純ですが冗長な実装が必要です。「繰り返さないでください」に近づく1つの方法は、T4を使用してコードを生成することです。

次のサンプルをテストするには、VSにクラスを追加しますが、拡張子を.csから.ttに変更します。これで、.ttファイルに接続された.ttファイルと.csファイルの2つのファイルが取得されます。

.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 に答える