0

Windowにリストされているさまざまなタイプのイベントを伝播するクラスを作成しています

enum Event {WINDOW_ClOSE=0x1, WINDOW_REDRAW=0x2, MOUSE_MOVE=0x4, ...}; 

ウィンドウで通知登録されているオブジェクトへ。イベントの種類ごとに、通知を許可するためにオブジェクトが拡張する必要がある抽象クラスがあります。たとえば、イベントに反応するために、私のオブジェクトは、によって呼び出されるメソッドを持つMOUSE_MOVEから継承します。多くのイベントをリッスンすることは、これらのクラスを複数拡張することで組み合わせることができます。これらのクラスはすべて基本クラスから継承されます。オブジェクトを登録するには、私は呼び出しますMouseMoveListenerprocess_mouse_move_event()WindowEventListener

void Window::register(EventListener* object, int EventTypes)
{
    if(EventTypes&WINDOW_CLOSE)
       /* dynamic_cast object to WindowCloseListener*, add to internal list of all
          WindowCloseListeners if the cast works, else raise error */

    if(EventTypes&MOUSE_MOVE)     
       /* dynamic_cast object to MouseMoveListener*, add to internal list of all
          MouseMoveListeners if the cast works, else raise error */

    ...
} 

これは問題なく動作しますが、私の不満は、それEventListener完全に空であり、コードの臭いがすることです。EventListener完全に削除してイベントの種類ごとに個別に設定することでこれを回避できることはわかっていますが、これによりWindow::registerインターフェイスが不必要に破壊されると思います (特に、以外の方法registerで同じ問題が発生する可能性があるため)。したがって、次のいずれかの答えを探していると思います。

  • 「あなたは今まで通りの方法でそれを続けることができます。なぜなら...」または

  • 「とにかく別々のWindow::register方法を導入してください。なぜなら...」またはもちろん

  • 「あなたはそれをすべて間違っています、あなたはすべきです...」。

編集:

EventListenerIgors コメントのリンクから: 上記のことは、たとえば仮想デストラクタに少なくとも 1 つの仮想メンバーがある場合にのみ機能する ため、クラスは技術的に完全に空ではありません。

編集2:

nmのソリューションを「私はすべて間違っている」タイプの1つとして時期尚早に受け入れました。ただし、これは 2 番目のタイプです。EventListener->register(Window&)ポリモーフィックに呼び出すことができたとしても、選択的な通知を登録Windowできる非常に冗長なインターフェイス (宣言されたメソッドに関して) を実装する必要があります。EventListenersこれは、上記の代替ソリューションと同等ですが、EventListener正当な理由なくクラスを追加で導入するだけです。結論として、標準的な答えは次のようです。

似たような関数をたくさん宣言するのを避けるためだけに + 空の基本クラスを実行しないでくださいdynamic_cast。後でコードを保守するときに問題が発生します。多くの関数を書きます。

編集3:

私にとって満足のいく解決策(テンプレートを使用)を見つけました。空の基本クラスを使用しなくなり、nm によって指摘されたメンテナンスの問題が発生しなくなりました。

4

2 に答える 2

2
object->registerWindow (this, EventTypes);

もちろんregisterWindow、すべてのEventListener継承者に対して実装する必要があります。関連するイベントの種類をチェックしてもらいます

アップデート

これがコードを再設計する必要があることを意味する場合は、コードを再設計する必要があります。なぜそうなのですか?スイッチオンタイプを行う適切な方法でdynamic_castないためです。これは適切な方法ではありません。階層にクラスを追加するたびに、古いコードの動的キャストによるすべてのスイッチを調べて更新する必要があるからです。これは非常に面倒で、すぐに保守できなくなります。これがまさに、仮想関数が発明された理由です。

仮想関数でスイッチオンタイプを行う場合、階層を変更するたびに何もする必要はありません...何もしません。仮想呼び出しメカニズムが変更を処理します。

于 2013-10-16T18:49:59.737 に答える