GUI を実装するとき、私はしばしばジレンマに遭遇します。いくつかの子ウィジェットを持つメイン ウィンドウを持つ単純なウィジェット階層があるとします。子ウィジェットはイベント (たとえば、ユーザー入力から発生) を処理する必要がありますか、それとも処理を親ウィジェットに委譲する必要がありますか? 簡単な例を次に示します。閉じるボタンがクリックされたときにウィンドウを閉じる必要があります。窓を閉めるのは誰?ウィンドウはボタン イベントに反応して閉じますか? または、ボタンはウィンドウの Close メソッドを呼び出しますか? 私が使用しているフレームワークは、子ウィジェットが親ウィジェットにイベントを発生させることが好ましい方法であることを強く示唆しており、親ウィジェットは適切に処理する必要があるため、ウィンドウは次のように閉じます (C++ 風の擬似コード):
void ChildWidget::OnClick()
{
GetParentWidget()->OnEvent(CreateClickEvent(*this));
}
void ParentWidget::OnEvent(Event& _event)
{
if (_event.Type() == EventTypeClick && _event.Id() == "close_button")
{
Close();
}
else if ...
...
}
しかし、それは単一責任の原則を破り、親ウィジェットが過大な作業を行うことにつながるのではないかと心配しています。代わりに、次のように、イベントを処理するために必要なオブジェクトを子ウィジェットに与えることができます。
class CloseButtonWidget : public Widget
{
public:
CloseButtonWidget(Widget& widget_to_close)
: WidgetToClose_(&widget_to_close)
{}
void OnClick()
{
WidgetToClose->Close();
}
private:
Widget* WidgetToClose_;
};
私が見ることができる欠点は、多くの場合、そのような自己処理ウィジェット用の新しいクラスを作成する必要があることですが、とにかく子ウィジェット用の新しいクラスを作成する必要があることが多いため、多くの場合、それはそれほど問題ではありません.
私が考えることができる別の方法は、子ウィジェットに次のようなコールバックを与えることです:
auto close_widget = new Widget();
// Suppose parent_widget is in scope
auto handler = CreateHandler(EventTypeClick, [parent_widget](){ parent_widget->Close(); });
close_widget->SetHandler(handler);
問題は、子ウィジェットからのイベントを処理するのに最適な場所はどこかということです。上記の方法の長所と短所は何ですか?たぶん、これを行うための他のより良い方法がありますか?「親ウィジェットがすべてを処理する」シナリオの長所を聞くことに特に興味があります。私が使用しているフレームワークの好みの方法と癖を維持しながら、より「哲学的な」方法で質問に対処する回答が必要であることを明確にしたいと思います(より良い設計とは何かなど)重要。