3

これは基本的な OOP の質問だと思います。完全に異なるメッセージ形式がいくつかあるメッセージ パッシング システムを設計していますが、それらすべてを PriorityBlockingQueue に配置できるようにしたいと考えています。最初に考えたのは、 を定義してabstract class Messageから、各メッセージ タイプの Message を拡張するサブクラスを定義することでした。ただし、これは、受信側で、メッセージ プロセッサがメッセージの内容を処理する方法を知るためにサブクラスを識別する必要があることを意味します。そして、私がこれを行う唯一の方法は.instanceof()orClass.を使用することであり、どういうわけか正しくないようです。

スコット・マイヤーズが書いているように、

「オブジェクトが T1 型の場合は何かを行い、T2 型の場合は別のことを行う」という形式のコードを書いていることに気付いたときはいつでも、自分を叩いてください。

(彼は続けて、ポリモーフィズムでは、サブクラスごとに異なる実装を持つ同じメソッド名を使用する必要があると主張しています。私の場合、そのアイデアを機能させる方法がわかりません-メッセージタイプ自体はまったく無関係です.)

議論のために、ここに私のメッセージタイプがあります:

  • ConsoleObject と ObjectState を識別する ConsoleMessage。
  • CardReaderRequestMessage には何も含まれていませんが、単に「次のカード」を要求しています
  • byte[80] カード イメージと Last Card インジケータを含む CardReaderMessage
  • byte[80] カード画像を含む CardPunchMessage
  • CardPunchResponseMessage には、カード イメージがパンチ バッファにコピーされたことを示す以外は何も含まれていません。

私は自分が扱っているメッセージの種類を知る必要があると信じているので、ポリモーフィック メッセージを使用するべきではないと思います。これを適切に設計するにはどうすればよいですか?

===== 編集してフォローアップの質問をする =====

私は、ある時点でそのサブクラスを特定することなく、ポリモーフィック メッセージを使用する方法を見つけようとしていました。提案されたアプローチはprocess()、各サブクラスでメソッドをオーバーライドすることでした。これが私の(単純化された)抽象メッセージと2つのサブクラスです:

public abstract class Message {

    public abstract void process() {
        // subclasses of Message implement this
    }

    public static class ConsoleMessage extends Message {
        private int obj;
        private int state;
        public ConsoleMessage(int x, int y) {
            obj = x;
            state = y;
        }
        @Override
        public void process() {
            // do something with obj and state?
        }

    public static class CardReaderMessage extends Message {
        private byte[] card;
        private boolean lastCardIndicator;
        public CardReaderMessage(byte[] c, boolean lc) {
            card = c;
            lastCardIndicator = lc;
        }
        @Override
        public void process() {
            // do something with card and lastCardIndicator
        }
}

すべての「インバウンド」メッセージに対して、スレッドごとに 1 つのキューがあります。スレッドがコンソールからのメッセージを「再開」するのを待つ必要があるが、その間に他のメッセージ タイプを受信して​​処理する必要があるとします。

waitForResumeMessage() {
    while (true) { // the following will block until a msg arrives
        Message msg = inboundMessageQueue.receiveMessage();
        msg.process();    

しかし、今は何ですか?process() の一部の実装により、一部のデータがどこかに移動されましたが、最終的には次のように記述できる必要があります。

        if // msg was ConsoleMessage "resume" command
            return;  // .. from waitForResumeMessage()
    } // else iterate until another message
}

これは基本的に、「msg」が属するクラスを見つけることを意味します。

私はこれにすべて間違って近づいていますか?「イベント駆動型」モデルでは「待機」はあまり適切ではないことを認識していますが、これは長時間実行されるバックグラウンド ワーカーです。おそらく、process() を使用するという考えは、イベント駆動型スレッドを導く FSM の状態を変更するのにより便利でしょうか?

4

4 に答える 4

2

あなたは狂っていません。その議論:

「オブジェクトが T1 型の場合は何かを行い、T2 型の場合は別のことを行う」という形式のコードを書いていることに気付いたときはいつでも、自分を叩いてください。

は話の一面にすぎません。話の反対側は、関心の分離を維持することが同じくらい (それ以上ではないにしても) 重要であるということです。一般的な例は、モデルがポリモーフィックに処理できるという理由だけで、プレゼンテーション コードをモデルに追加すべきではないということです。残念ながら、Java 言語は、両方の理想を同時に達成する上であまり役に立ちません。

「並列だが分離された」コードを維持する方法はたくさんあります。Visitor パターンは、大きなスイッチまたは if-instance-of ブロックと同様に 1 つです。別のオプションは、Map具象クラスから具象クラスへの変換です。

于 2011-07-23T04:52:27.803 に答える
1

すでに提案されているソリューションに加えて、インターフェースや抽象クラスなしでそれを実行できることを言及したいと思います。

メッセージオブジェクトを処理できる情報を含む独自の注釈を作成できます。

実装時: それに応じてクラスに注釈を付けます。

実行時: キューから次の要素をポップすると、注釈を調べて、現在のインスタンスを処理できる実装を呼び出すことができます。

于 2011-07-23T08:38:23.060 に答える
1

あなたのアイデアは良いです。実際には、抽象クラスまたは Message と呼ばれるインターフェイスから始める必要があります。このインターフェイスは次のようになります。

     public interface Message {
     void process();
     //some other methods
}

public class MessageType1  implements Message {
    @Override
    public void process() {
      //My special way to process this message
}
}

このように、受信側は IS A Message 、つまり Message インターフェイスを実装するものを受信するだけでよく、特定のメッセージの種類は気にしなくても、処理に応答するだけなので、それぞれの特定の方法を実装するだけで済みます。メッセージはそこで処理する必要があります。

于 2011-07-23T04:51:17.157 に答える
1

必要なのはテンプレート メソッドです。つまり、受信側が同じインターフェイスを使用して呼び出したいメッセージメソッドを定義しますが、実際のオブジェクトのタイプに基づいて、メッセージのタイプのいずれかでオーバーライドされたメソッドが実際に呼び出されます。

于 2011-07-23T04:52:19.970 に答える