監視コントローラー

UIをビューとコントローラーに分割します。ビューは基となるモデルへの単純なマッピングを処理し、コントローラーは入力応答と複雑なビューロジックを処理します。

これは、2000年代半ばに執筆していた「エンタープライズアプリケーションアーキテクチャ開発の更なる発展」の一部です。残念ながら、それ以来、多くの他のことが私の注意を奪ってきたため、それ以上取り組む時間がありませんでしたし、近い将来、時間を見つけることも難しいでしょう。そのため、この資料は非常にドラフト段階のものであり、再び作業に取り組めるようになるまで、修正や更新を行う予定はありません。

多くのUIフレームワークは、ビューとモデル間のマッピングを容易にする機能を提供しており、多くの場合、何らかのデータバインディングを使用しています。これらのアプローチは、ビューとモデルの要素間の関係を宣言的に設定することを可能にする上で非常に効果的です。しかし、通常、より複雑な関係があり、より複雑なビューロジックが必要になる場合もあります。このロジックは管理が難しく、特にビューに埋め込まれている場合はテストが困難です。

監視コントローラーは、入力応答を処理するだけでなく、より複雑なビューロジックを処理するためにビューを操作するコントローラーを使用します。単純なビューの動作は宣言型システムに任せ、宣言的に達成できる範囲を超える効果が必要な場合にのみ介入します。

動作方法

監視コントローラーは、プレゼンテーション機能をコントローラー(プレゼンターと呼ばれることが多い)とビューの2つの部分に分解します。表示する必要があるドメインデータは別個のものであり、大まかなMVC用語に従ってモデルと呼びますが、ドメインモデルである必要はありません。責任のこの基本的な分割は、バウアーとマクグラスハンによって記述されている、そのドルフィン形式のModel-View-Presenterアーキテクチャを反映しています。

監視コントローラーには、入力応答と部分的なビュー/モデルの同期という2つの主要な役割があります。

入力応答に関しては、コントローラーはプレゼンタースタイルで動作します。ユーザーの操作は最初は画面ウィジェットによって処理されますが、それらが応答として行うのは、これらのイベントをプレゼンターに渡すだけであり、プレゼンターはそれ以降のすべてのロジックを処理します。

ビュー/モデルの同期に関しては、コントローラーは可能な限りビューに任せます。ビューは通常、何らかのデータバインディングを使用して、フィールドの情報の多くを生成します。 データバインディングがより複雑なインタラクションに対応できない場合、コントローラーが介入します。

図1:評価例に関するクラス図。

図2:低い実際値を入力した場合の応答を示すシーケンス図。

評価ウィンドウでは、最初のテキスト変更はビュー内のテキストフィールドウィジェットによって処理されます。このウィジェットはコントローラーによって監視されているため、テキストが変更されると、ウィジェットはイベントを発行し、コントローラーの`actualFieldChanged`メソッドが呼び出されます。このメソッドは、イベントへの完全な応答を処理します。まず、readingモデルオブジェクトの実際値を更新します。ウィンドウはreadingオブジェクトを監視しているため、readingの値の変更によって更新がトリガーされます。実際値と差異テキストフィールドのテキストをreadingの適切なプロパティにマッピングするのは非常に簡単なので、それらの値を更新します。この例では、色の変更はもう少し複雑です。readingオブジェクトは、readingがどのカテゴリに分類されるべきかを判断できますし、そうすべきです。洗練されたウィジェットであれば、このようにテキストの色をカテゴリにバインドできるかもしれませんが、そのような賢いものは持っていないと仮定しましょう。この場合、コントローラーは差異フィールドのテキストの色を直接設定します。

例が示すように、優れた監視コントローラーの本質は、できるだけ少ない作業を行うことです。ビューができるだけ多くの処理を行い、より複雑なロジックが必要な場合にのみ介入します。

監視コントローラーを使用する主な理由の1つは、テスト容易性です。ビューがテストしにくいと仮定すると、複雑なロジックをコントローラーに移動することで、テストしやすい場所にロジックを配置できます。ただし、コントローラーのテストを実行するには、何らかの形式のビューが必要なので、テストダブルが必要になることがよくあります。ダブルがあれば、UI動作のより厄介な部分をテストするために、UIフレームワークオブジェクトは必要ありません。

このテスト容易性の問題は、コントローラーがビューとそのウィジェットに直接アクセスするのか、仲介者を通じてアクセスするのかという別の決定にも影響します。仲介者を使用すると、コントローラーを操作するためのゲートウェイを構築します。次に、ゲートウェイの1つの実装はウィンドウのインターフェースに適応し、もう1つはテスト用のスタブを提供します(モックを使用することもできます)。これは、パッシブビューに必要なのと同じアプローチです。

図3:コントローラーとウィンドウ間の仲介者を使用。

これまでの議論では、監視コントローラーフロー同期を使用することを示唆していますが、そうする必要はありません。 オブザーバー同期を使用することもできますが、ビューではなくコントローラーがモデルを監視するように変更する必要があります。

いつ使用するのか

監視コントローラーの使用を検討する主な理由は2つあります。自律ビューの複雑さを分離することと、テスト容易性を向上させることです。

分離の利点は、基本的なウィンドウ自体からすべての動作の複雑さを取り除き、理解しやすくなることです。この利点は、コントローラーはまだ画面と密接に結合されており、画面の詳細についてかなり詳細な知識が必要であるという事実によって相殺されます。その場合、それを別のオブジェクトにする価値があるかどうかについて、本当に疑問符が付きます。

テスト容易性の理由は、より説得力があります。私が話した多くの人が、何らかの形式のコントローラーを使用することで、適切にテスト可能なUIを作成する上で大きな違いが生じたと感じています。

テスト容易性が推進要因である場合、重要な問題は、ビューに残す動作の量です。パッシブビュー監視コントローラーと非常によく似たパターンですが、パッシブビューは単純なケースも含め、すべてのビュー更新動作をコントローラーに配置するという違いがあります。これにより、プログラミングのオーバーヘッドが増えますが、すべてのプレゼンテーション動作をテスト可能にすることができます。どちらを選択するかは、どのようなデータバインディングサポートがあるか、コントローラーテストでそれをテストしないことを問題ないかどうかによって異なります。

3番目の選択肢はプレゼンテーションモデルです。これもまた、ビューからほとんどの動作を取り除きますが、すべての更新を同期させるのはビューの役割のままです。プレゼンテーションモデル監視コントローラーの間のテストカバレッジには大きな違いはありません。多くの選択(パッシブビューと同様)は、個人の判断によって異なります。