メッセージタイプに基づいて異なる処理を処理する方法
-
03-07-2019 - |
質問
「通知」するプロセスがあります。メッセージタイプの基本クラスをパラメーターとして受け取るメソッド。メッセージの派生タイプに基づいて異なる処理を行いたいです。これは、「プロセス」というメソッドを追加する必要があるということですか?またはメッセージタイプに似たもので、ポリモーフィズムを使用して呼び出しますか? 「通知」を追加する方が良いですか?特定のメッセージタイプごとに
詳細:言語はC ++です。ここでは、通知することをお勧めします。したがって、さまざまなメッセージタイプを通知するために必要なメソッドは1つだけです。コントローラーは、純粋なvitual notify(MsgBaseClass)メソッドを指定するリスナークラスから継承します。新しいメッセージタイプごとに通知を追加する必要がないので、私は今でもそのアイデアが好きです。しかし、コントローラーのコード自体には、動的キャストなどのメッセージタイプ以外のメッセージタイプを区別する方法や、メッセージにメッセージタイプを追加する方法がありません。
編集:訪問者パターンを使用すると思います。これにより、通知用のメソッドを1つだけ保持でき、コード内のswitchステートメントを回避できます。 「訪問者」インターフェイスは、さまざまな派生メッセージタイプを処理するためにリスナーが必要とするさまざまなメソッドを指定します。これには、Message基本クラスに追加するメッセージが1つだけ必要です。純粋な仮想" accept(MyMessageTypeVisitor v)です。派生メッセージクラスは、v.visit(this);
を使用して実装します。私はこのはずの仕事を考える。
解決
従来のOOの回答では、具体的なメッセージサブクラスがオーバーライドして特定の処理を提供する抽象メソッドを提供するために、ベースメッセージクラスが必要です。
DylanやCLispなどの一部の(あまり普及していない)言語は、「汎用関数」を提供します。 (引数の型に応じて動的にディスパッチされます)これにより、問題が大幅に解決されます。
ポピュラーな言語で実行可能な柔軟なアプローチの1つは、ボブおじさんの「非周期的訪問者」です。デザインパターン、 http://www.objectmentor.com/resources/articles/acv.pdf ;その他の訪問者のバリアントについては、www.ccs.neu.edu / research / demeter / adaptive-patterns / visitor-usage / papers / plop96 / variations-visitor-nordberg.psを参照してください。
他のヒント
編集:率直に言って良い点があり、そのメッセージは自分自身を処理する方法を知らないはずだと思います。したがって、メッセージをファクトリーとして使用できる場所について説明したアプローチは、良いアイデアではありません。ただし、抽象的なプロセスファクトリが良い解決策になると思います。
抽象ファクトリーを使用して、処理を処理できるオブジェクトを作成し、ポリモーフィズムを使用して呼び出します。このファクトリは、メッセージクラスに直接含めることができます。または、メッセージタイプをパラメータとして受け入れ、適切なオブジェクトを返す別のファクトリクラスを作成できます。
class Message {
public:
virtual Processor *getProcessor() = 0;
// other methods
};
class Processor {
public:
virtual void doWork() = 0;
};
class MyListener : Listener {
public:
void notify(Message *message);
};
void MyListener::notify(Message *message) {
Processor *proc = message->getProcessor();
proc->doWork();
};
(これが間違っている場合はごめんなさい。私のC ++は少し弱いですが、原理を示していると思います。)
これにより、メッセージタイプごとにgetProcessor()をオーバーライドし、適切なプロセッサを作成できます。
IMVHO、ポリモーフィズムが進むべき道です。あなたがしたい処理ロジックの種類は、メッセージクラスに属しておらず、別のクラスに移動する必要があると思います。私がこのアプローチを好むもう1つの理由は、メッセージを追加しても通知されるクラスの構造を変更する必要がないことです。メッセージタイプが1つまたは2つしかない場合、これは問題にならない可能性があります。
次のようなことができます:
DerivedType *dt = dynamic_cast< DerivedType >( &BaseType );
if( dt != NULL )
{
// Handle processing of DerivedType
}
処理された各DerivedTypeに対してdynamic_castを実行してみてください。 NULL以外のポインターを取得する場合、キャストしようとした型を受け取ったことを知っています。
オブザーバーのデザインパターンにこだわっていますか?
オーバーロードされた notify
は候補のように見えます。オブザーバーパターンは本当にシンプルです。これは、ハリウッドの原則、つまり&quot;電話しないでください。あなた!&quot;。アイデアは、オブジェクトのセット(オブザーバー)を用意し、クエリを実行する代わりにそれらに通知することです。汎用の Event
種類のデータをオブザーバーに渡します。これをどうするかを決めるのは、オブザーバーに任されるべきです。オブザーバーが異なるイベントに反応する場合は、 dynamic_casts
があります(はい、イベント階層も必要です)。