2

私は次の基本インターフェースを持っています

public interface IHandler{
  void Handle(IMessage message);
}

およびベースインターフェイスを継承する汎用インターフェイス

public interface IHandler<TMessage> : IHandler where TMessage : IMessage{
  void Handle(TMessage message);
}

IHandler<TMessage>私のクラスは、インターフェースを複数回実装できます。IMessageはメッセージの基本インターフェースであり、ここでは関係ありません。現在、私は次のようにインターフェースを実装しています。

public class ExampleHandler : IHandler<ExampleMessage>, IHandler<OtherExampleMessag>{

  void IHandler.Handle(IMessage message){
    ExampleMessage example = message as ExampleMessage;

    if (example != null) {
      Handle(example);
    }
    else {
      OtherExampleMessage otherExample = message as OtherExampleMessage;

      if (otherExample != null) {
        Handle(otherExample);
      }
  }

  public void Handle(ExampleMessage) {
   //handle message;
  }

  public void Handle(OtherExampleMessage) {
   //handle message;
  }
}

私を悩ませているのは、メソッドを実装するHandle(IMessage)方法であり、私の意見では多くの冗長なコードを引き起こしIHandler<TMessage>、クラスに新しいインターフェイスを実装するたびにメソッドを拡張する必要があります。

私が探しているのは、メソッドを実装するためのより一般的なHandle(IMessage)方法です(おそらく、ハンドラーの基本クラスにあります)が、現在、その方法に固執しています。

4

4 に答える 4

3

newdynamicキーワードを使用して、過負荷の解決をDLRに移動できます。

void IHandler.Handle(IMessage message)
{
    dynamic d = message;
    Handle(d);
}

RuntimeBinderException渡されたメッセージがクラスに対して有効でない場合、これは実行時に失敗することに注意してください。
この例外を回避するために、すべての不明なメッセージタイプのハンドラーを追加できます。

private void Handle(object unknownMessage)
{
    // Handle unknown message types here.
}

基本クラスに実装IHandler.Handleするには、もう少し作業を行う必要があります。

public class BaseHandler : IHandler
{
    void IHandler.Handle(IMessage message)
    {
        dynamic d = message;
        Handle(d);
    }

    private void Handle<TMessage>(TMessage message) where TMessage : IMessage
    {
        var handler = this as IHandler<TMessage>;
        if(handler == null)
            HandleUnknownMessage(message);
        else
            handler.Handle(message);
    }

    protected virtual void HandleUnknownMessage(IMessage unknownMessage)
    {
        // Handle unknown message types here.
    }
}

特定のハンドラーは次のようになります。

public class ExampleHandler : BaseHandler,
                              IHandler<ExampleMessage>,
                              IHandler<OtherExampleMessage>
{
    public void Handle(ExampleMessage message)
    {
        // handle ExampleMessage here
    }

    public void Handle(OtherExampleMessage message)
    {
        // handle OtherExampleMessage here
    }
}

このコードは次のように機能します。

  1. DLRは、実際のメッセージタイプを使用してジェネリックBaseHandler.Handle<TMessage>メソッドを呼び出します。つまり、ではTMessageなくIMessage、のような具体的なメッセージクラスを呼び出しますExampleMessage
  2. このgeneircハンドラーメソッドでは、基本クラスは特定のメッセージのハンドラーに自分自身をケースに入れようとします。
  3. それが成功しない場合はHandleUnknownMessage、不明なメッセージタイプを処理するために呼び出します。
  4. キャストが成功するとHandle、特定のメッセージハンドラーのメソッドが呼び出され、その呼び出しが具体的なHandler実装に効果的に委任されます。
于 2012-10-12T09:29:19.593 に答える
1

あなたのクラス(質問)が複数のことをしているので、あなたは立ち往生しています。とを扱っていExampleMessageますOtherExampleMessage。1つのことを処理するために1つのクラスを作成することをお勧めします。

例:

public class ExampleHandler : IHandler<ExampleMessage> 

public class OtherExampleHandler : IHandler<OtherExampleMessag>

私の理解では、ある種のイベントを処理するクラスが必要です。この場合、オブザーバーパターンを使用して、何かが発生したときに各ハンドラーに通知し、ハンドラーに作業を任せる必要がある場合があります。

于 2012-10-12T09:33:56.243 に答える
1

合理的な方法は、リフレクションを賢明に使用することです。

var method = this.GetType().GetMethod("Handle", new[] { message.GetType() });

if (method != null) {
    method.Invoke(this, new[] { message });
}

パフォーマンスが問題になるほどこれを行っている場合は、テストの結果をキャッシュして大幅な改善を行うことができます。

于 2012-10-12T09:27:42.523 に答える
-1

インターフェイスは、N個のサービスを提供するインスタンスがあることを示しています。確かにサービスは似ていますが、タイプが異なるため、独立したサービスです。したがって、「コードの臭い」を検出します。匂いは「なぜ異なるサービスの一般的な方法なのか?」です。

では、サービスは、ジェネリックインターフェイス宣言を正当化するのに十分なほど異なっていますか?ここでの基本は「複製」です。重複をリファクタリングします。複製は悪いです。重複したものを移動すると、答えは自明になります。

別の言い方をすれば、共通のメソッドを取り除き、それぞれを独自のメソッドで処理します...複製は、別のクラスに移動したいものです。もしそうなら、注射を考えてください。

あなたの匂いの検出が大好きです!

于 2012-10-12T09:33:57.530 に答える