9

クライアント クラスが受信するメッセージの種類に基づいて異なる動作を実行する次のような状況があります。instanceof ステートメントと if ステートメントが気に入らないので、これを行うためのより良い方法があるかどうか疑問に思っています。

私が考えたことの 1 つは、メソッドをクライアント クラスから引き出してメッセージに入れることでした。IMessage インターフェイスに process() のようなメソッドを配置し、具体的なメッセージ タイプのそれぞれにメッセージ固有の動作を配置します。これにより、タイプをチェックするのではなく message.process() を呼び出すだけなので、クライアントが単純になります。ただし、これに関する唯一の問題は、条件に含まれる動作が Client クラス内に含まれるデータの操作に関係していることです。したがって、具体的なメッセージ クラスにプロセス メソッドを実装した場合、それをクライアントに渡す必要があり、これが本当に意味があるかどうかもわかりません。

public class Client {
    messageReceived(IMessage message) {
        if(message instanceof concreteMessageA) {
            concreteMessageA msg = (concreteMessageA)message;
            //do concreteMessageA operations
        }
    }
        if (message instanceof concreteMessageB) {
            concreteMessageb msg = (concreteMessageB)message;
            //do concreteMessageB operations
        }
}
4

6 に答える 6

7

instanceof テストを回避する簡単な方法は、ポリモーフィックにディスパッチすることです。例えば

public class Client {
    void messageReceived(IMessage message) {
        message.doOperations(this);
    }
}

ここで、各メッセージ クラスは適切なdoOperations(Client client)メソッドを定義します。

編集:要件によりよく一致する2番目のソリューション。

「instanceof」テストのシーケンスを switch ステートメントに置き換える代替手段は次のとおりです。

public class Client {
    void messageReceived(IMessage message) {
        switch (message.getMessageType()) {
        case TYPE_A:
           // process type A
           break;
        case TYPE_B:
           ...
        }
    }
}

各 IMessage クラスはint getMessageType()、適切なコードを返すメソッドを定義する必要があります。Enum は int と同様に機能し、IMO よりもエレガントです。

于 2009-08-10T04:08:33.690 に答える
5

ここでの1つのオプションは、ハンドラーチェーンです。ハンドラーのチェーンがあり、各ハンドラーはメッセージを処理して(該当する場合)、それを消費できます。つまり、メッセージはチェーンの下位に渡されません。まず、Handlerインターフェースを定義します。

public interface Handler {
    void handle(IMessage msg);
}

そして、ハンドラチェーンロジックは次のようになります。

List<Handler> handlers = //...
for (Handler h : handlers) {
    if (!e.isConsumed()) h.handle(e);
}

次に、各ハンドラーはイベントの処理/消費を決定できます。

public class MessageAHandler implements Handler {
    public void handle(IMessage msg) {
        if (msg instanceof MessageA) {
            //process message
            //consume event 
            msg.consume();
        }
    }
}

もちろん、これはsを取り除くことはありません-しかし、それはあなたが読めない可能性がinstanceofある巨大なブロックを持っていないことを意味しますif-elseif-else-if-instanceof

于 2009-08-10T06:23:57.613 に答える
1

どのタイプのメッセージ システムを使用していますか?

多くの場合、メッセージ ヘッダーまたはコンテンツに基づいてハンドラにフィルタを追加するオプションがあります。これがサポートされている場合は、メッセージ タイプに基づいたフィルターを使用してハンドラーを作成するだけで、instanceof やタイプのチェックを必要とせずに (メッセージング システムによって既にチェックされているため)、コードは適切でクリーンです。

JMS または OSGi イベント サービスでこれを実行できることはわかっています。

JMS を使用しているため、基本的に次のようにしてリスナーを登録できます。これにより、一意のメッセージ タイプごとにリスナーが作成されます。

  String filterMsg1 = "JMSType='messageType1'";
  String filterMsg2 = "JMSType='messageType2'";

  // Create a receiver using this filter
  Receiver receiverType1 = session.createReceiver(queue, filterMsg1);
  Receiver receiverType2 = session.createReceiver(queue, filterMsg2);

  receiverType1.setMessageHandler(messageType1Handler);
  receiverType2.setMessageHandler(messageType2Handler);

これで、各ハンドラーは特定のメッセージ タイプのみ (instanceof または if-then なし) を受信します。もちろん、送信者が送信メッセージで setJMSType() を呼び出してタイプを設定すると仮定します。

このメソッドはメッセージに組み込まれていますが、もちろん、独自のヘッダー プロパティを作成し、代わりにそれをフィルター処理することもできます。

于 2009-08-10T14:09:09.573 に答える
0
//Message.java

abstract class Message{
     public abstract void doOperations();
 }

//MessageA.java

 class MessageA extends Message{
    public void doOperations(){ 
         //do concreteMessageA operations ;
    }
 }

   //MessageB.java

class MessageB extends Message {
     public void doOperations(){ 
         //do concreteMessageB operations 
     }
}

//MessageExample.java

class MessageExample{
   public static void main(String[] args) {
        doSmth(new MessageA());
    }

    public static void doSmth(Message message) {
       message.doOperations() ;     

     }
}   
于 2010-08-11T08:20:42.410 に答える