ボブおじさんは彼の本「クリーンアーキテクチャ」で、プレゼンターは受け取ったデータを「ビューモデル」と呼ぶものに入れる必要があると述べています。
これは、Model-View-ViewModel(MVVM)設計パターンの「ViewModel」と同じですか、それとも単純なデータ転送オブジェクト(DTO)ですか?
単純なDTOではない場合、ビューとどのように関係しますか?ビューは、オブザーバー関係を介してビューから更新を取得しますか?
私の推測では、彼の本の第23章でRobert Martinは次のように述べているため、MVVMのViewModelに似ていると思います。
[プレゼンターの]ジョブは、アプリケーションからデータを受け取り、それをプレゼンテーション用にフォーマットして、ビューが単純に画面に移動できるようにすることです。たとえば、アプリケーションがフィールドに日付を表示したい場合、PresenterにDateオブジェクトを渡します。プレゼンターは、そのデータを適切な文字列にフォーマットし、ビューモデルと呼ばれる単純なデータ構造に配置します。ビューはそれを見つけることができます。
これは、(たとえば、DTOの場合のように)ビューを関数の引数として単に受け取るのではなく、ビューが何らかの形でViewModelに接続されていることを意味します。
私がこれを考えるもう1つの理由は、画像を見る場合、プレゼンターはビューモデルを使用しますが、ビューをではないためです。プレゼンターは出力境界と出力データDTOを両方使用します。
DTOでもMVVMのViewModelでもない場合は、詳しく説明してください。
これは、Model-View-ViewModel(MVVM)設計パターンの「ViewModel」と同じですか?
いいえ。
this :
それには循環があります。ボブおじさんは 注意深くサイクルを避けている です。
代わりにこれがあります:
確かにサイクルはありません。しかし、ビューが更新についてどのように認識しているのか疑問に思います。それについてはすぐに説明します。
それとも単純なデータ転送オブジェクト(DTO)ですか?
前のページからボブを引用するには:
必要に応じて、基本的な構造体または単純なデータ転送オブジェクトを使用できます。または、ハッシュマップにパックしたり、オブジェクトに構築したりできます。
クリーンアーキテクチャp207
ですから、よろしければ。
しかし、私が本当にあなたを悩ませているのは this だと強く思います:
このUMLのかわいい悪用は、ソースコードの依存関係の方向と制御の流れの方向を対比させます。これがあなたの質問に対する答えが見つかる場所です。
使用関係では:
制御の流れは、ソースコードの依存関係が行う方向と同じです。
実装関係では:
制御の流れは通常、ソースコードの依存関係とは逆の方向に進みます。
これはあなたが本当にこれを見ていることを意味します:
制御のフローがプレゼンターからビューに渡ることは決してないことがわかるはずです。
それはどうしてですか?どういう意味ですか?
これは、ビューに独自のスレッドがあることを意味します(これは珍しいことではありません)、または(@Euphoricが指摘するように)制御のフローがここに示されていない他の何かからビューに入ってきています。
同じスレッドの場合、ViewはView-Modelを読み取る準備ができたことを認識します。しかし、それが事実であり、ビューがGUIである場合、ユーザーがDBを待機している間にユーザーが画面を移動すると、画面の再描画が困難になります。
ビューに独自のスレッドがある場合は、独自の制御フローがあります。つまり、これを実装するには、ビューは変更を通知するためにビューモデルをポーリングする必要があります。
プレゼンターはビューが存在することを認識せず、ビューがプレゼンターが存在することを認識しないため、お互いに呼び出すことはできません。彼らはお互いにイベントを投げることはできません。起こり得るのは、プレゼンターがビューモデルに書き込み、ビューがビューモデルを読み取ることだけです。それがそのように感じる時はいつでも。
この図によると、ビューとプレゼンターが共有する唯一のものは、ビューモデルの知識です。そしてそれは単なるデータ構造です。したがって、動作を期待しないでください。
それは不可能に思えるかもしれませんが、ビューモデルが複雑な場合でも機能させることができます。 1つの小さな更新されたフィールドは、ビューが変更を検出するためにポーリングする必要があるすべてのフィールドです。
もちろん、オブザーバーパターンの使用を主張することも、フレームワークでこの問題を隠すこともできますが、そうする必要はないことを理解してください。
これが、制御のフローを示すのに少し楽しかったです。
フローが前に定義した方向に反するのを見るときはいつでも、あなたが見ているのはコールが戻ることです。そのトリックは、ビューに到達するのに役立ちません。さて、最初にコントローラーと呼ばれるものに戻らない限り。または、単に デザインを変更する にして、ビューにアクセスできるようにすることもできます。これは、データアクセスとそのインターフェイスの yo-yo問題 の始まりのように見えるものも修正します。
それ以外に、ここで学ぶべき唯一の他のことは、プレゼンターを最後に呼び出す限り、ユースケースインタラクターは、好きな順序でほとんどのことを呼び出すことができるということです。
マーティンのクリーンアーキテクチャとMVVMの両方を誤解していると思うので、この問題はあまりにも混乱し、適切に問題を説明するには多くのテキストと時間がかかります。
最初に注意すべきことは、投稿した図が不完全であることです。 「ビジネスロジック」のみを示していますが、実際にパーツを正しい順序で動かす何らかの「オーケストレーター」がありません。
オーケストレーターのコードは、
string Request(string request) // returns response
{
Controller.Run(data);
Presenter.Run();
return View.Run();
}
マーティンがクリーンアーキテクチャについての彼の講演の1つでこれについて話しているのを聞いたと思います。
もう1つ指摘すべきことは、サイクルの欠如に関するcandied_orangeの発言が間違っているということです。はい、循環しているコードはコードのアーキテクチャーには存在しません(存在してはいけません)。ただし、ランタイムインスタンス間のサイクルは一般的であり、多くの場合、設計がより単純になります。
それはMVVMの場合です。 MVVMでは、ViewはViewModelに依存しており、ViewModelはイベントを使用してViewに変更を通知します。つまり、クラスの設計では、ViewクラスからModelクラスへの依存関係のみが存在しますが、実行時には、ViewインスタンスとViewModelインスタンスの間に循環依存関係が存在します。このため、ViewModelはそれ自体をいつ更新するかを把握するためのViewの方法を提供するため、オーケストレーターは必要ありません。これが、この図の「通知」が直接線ではなく「波線」線を使用する理由です。これは、ViewがViewに依存しているのではなく、ViewがViewModelの変更を監視することを意味します。
MartinのClean Architectureから取るべき最も重要なことは、デザイン自体ではなく、依存関係の処理方法です。彼の講演で彼が語る重要なポイントの1つは、境界がある場合、その境界を越えるすべてのコード依存関係が単一方向でそれを越えるということです。図では、この境界は二重線で表されています。そして、コードの依存関係の方向を修正するインターフェース(InputBoundary
、OutputBoundary
およびDataAccessInterface
)を介した依存関係の逆転がたくさんあります。
対照的に、Clean ArchitectureのViewModel
は、ロジックのない単なるDTOです。これは<DS>
鬼ごっこ。そして、これがorchestrator
がロジックを実行するタイミングを知らないため、View
が必要な理由です。
実行時にダイアグラムを「フラット化」すると、次のようになります。
したがって、実行時、依存関係は「間違った」方向にありますが、それは問題ありません。
私は 彼のクリーンアーキテクチャについての話 を見て彼の推論をよりよく理解することをお勧めします。