web-dev-qa-db-ja.com

C ++でのコールバック実装に最適な設計はどれですか?

「親」というクラスがあります。 「親」クラスは、私のCPPモジュールに「子」クラスのオブジェクトを作成します。ユースケースは、「子」が「親」に情報を要求する必要がある場合です。これはいくつかの方法で行うことができ、私は以下の設計を考えることができます。

1)「子」に「親」のオブジェクトポインター/参照を格納し、「子」に「親」のいくつかのパブリックメソッドを呼び出させます。

2)「子」は、コールバックを登録するためのAPIを公開します。 「親」は、コールバックハンドルとして「this」ポインタを持つ静的関数を登録します。 「子」が情報を要求する場合、登録されたコールバック関数をコールバックハンドルを引数の1つとして呼び出します。コールバック関数は、「親」オブジェクトへのコールバックハンドルを逆参照し、情報を取得します。

誰かがどちらがより良いデザインであるか教えてもらえますか?また、私はこの種の問題の標準的な設計があることを知りたいですか?

6
MayurK

それはおそらく、オブジェクトをどれだけ強く結合するかに依存します。しかし、より迅速な開発とより読みやすいコードのためには、方法1が望ましいと思います。親への参照をウィークポインタとして保存するだけです(最新のC++を使用している場合)。

親が子内で関数を登録するパターンを実行できます(この場合、関数ポインターを公開するよりも、クロージャーとstd :: functionを優先します)。しかし、これらの2つのオブジェクトが情報を共有する必要がある唯一のオブジェクトである場合、親へのポインターを子オブジェクトに渡さないことには意味がなく、これは頻繁に使用されます。

最後に、可能であれば、単方向のデータフローを使用することをお勧めします。子供に情報を要求させるのではなく、親にそれを押し込ませます。これにより、インターフェースがより読みやすく安全になります(データを送信しても安全かどうかは親が常に知っているが、子は親の状態を認識していない可能性があるため)。また、すべてのデータを定数値として渡すことも簡単になります。

5
Jozef Legény

親へのポインタは有効なアプローチです。しかし、これは拡張するのが難しい非常に特殊なソリューションです。

より良いアプローチは observer design pattern を実装することです。それを行う方法の例はたくさんあります。 GoF リファレンスブック、または ここ から始めます。これは実際にはオプション2の一般的なクリーンな形式です(親はオブザーバー、子はサブジェクトです)。

それでもコールバックアプローチを好む場合は、 callback objects を選択することをお勧めします。

2
Christophe

オブジェクト指向の何かを試してください。

子に、親が実装する interface を渡します。これは循環データ構造を作成するため、正しい順序で解放する必要があります。他の言語では気にしないもの...

子が親(インターフェース)にアクセスする必要があるのは、よく知られた特定の時間だけであることがわかります。そのため、コンストラクタへのパラメータとしてではなく、子メソッドへのパラメータとしてそれを提供できます。

そうでない場合、子が親の変更に応答する必要がある場合は、 Observer パターンを検討してください。

1
Erik Eidt