クリーンアーキテクチャ:ビューモデルとは


13

彼の本「Clean Architecture」で、叔父ボブは、プレゼンターが受け取ったデータを「表示モデル」と呼ぶものに入れるべきだと言っています。

ここに画像の説明を入力してください

これは、Model-View-ViewModel(MVVM)設計パターンの「ViewModel」と同じものですか、それとも単純なデータ転送オブジェクト(DTO)ですか?

単純なDTO ではない場合、ビューにどのように関連しますか?ビューは、オブザーバー関係を通じて更新されますか?

私の推測では、彼の本の第23章でロバート・マーティンは次のように述べているため、MVVMのViewModelに似ていると思います。

[The Presenter's]ジョブは、アプリケーションからデータを受け取り、プレゼンテーション用にフォーマットして、Viewがデータを画面に簡単に移動できるようにすることです。たとえば、アプリケーションでフィールドに日付を表​​示する場合、プレゼンターにDateオブジェクトを渡します。プレゼンターは、そのデータを適切な文字列にフォーマットし、Viewモデルと呼ばれる単純なデータ構造に配置します。Viewモデルでは、データを見つけることができます。

これは、たとえばDTOの場合のように、単に関数引数として受け取るのではなく、Viewが何らかの方法でViewModelに接続されていることを意味します。

あなたは、画像を見れば、プレゼンターはビューモデルを使用しますが、ので、私はこれを考えるもう一つの理由はありませんビューを。一方、プレゼンターは出力境界と出力データDTOの両方を使用します。

DTOでもMVVMのViewModelでもない場合は、それが何であるかを詳しく説明してください。


答えは「それは依存する」だと思います。Webアプリケーションの場合、ビューモデルは最終的にHTML文字列としてシリアル化されるため、基本的にはDTOです。それ以外の場合、ビューモデルは、ビューにデータを表示するための特別なオブジェクトです。
グレッグブルクハート

MVVM(WPF、Winformsアプリケーション)ViewModelではのラッパーControllerPresenterありViewModel、Uncle BobのCleanアーキテクチャでは。
ファビオ

@Greg Burghardt-ViewModelが特殊なデータ構造である場合、Viewは変更をどのように通知されますか?
-Fearnbuster

@Fabio-あなたがMVVMパターンでViewModelはダイアグラムの一番左のグループ内にあるすべてのコンポーネントと同等であるというあなたの意味を正しく理解したら?それがボブおじさんのアーキテクチャに当てはまる場合、なぜ彼はコントローラーとプレゼンターを別々にリストするのですか?
-Fearnbuster

彼は、入力ハンドラと出力ハンドラを異なるオブジェクト/クラスに分離したと思います。MVVMでは、Controller-> ICommandおよびPresenter->になりdata-binding mechanismます。
ファビオ

回答:


17

これは、Model-View-ViewModel(MVVM)設計パターンの「ViewModel」と同じものですか

いや。

それは次のようになり、この

ここに画像の説明を入力してください

それにはサイクルがあります。ボブおじさんはサイクルを注意深く避けてきました。

代わりにこれがあります:

ここに画像の説明を入力してください

確かにサイクルはありません。しかし、ビューが更新についてどのように知っているのか疑問に思うでしょう。これについてはすぐに説明します。

それとも単純なデータ転送オブジェクト(DTO)ですか?

前のページからボブを引用するには:

必要に応じて、基本的な構造体または単純なデータ転送オブジェクトを使用できます。または、ハッシュマップにパックするか、オブジェクトに構築できます。

クリーンアーキテクチャp207

よろしければ

しかし、あなたが本当にあなたを悩ませているのはこれだと強く疑います:

ここに画像の説明を入力してください

UMLのこのちょっとした乱用は、ソースコードの依存関係の方向と制御の流れの方向を対比しています。これはあなたの質問に対する答えが見つかる場所です。

使用関係の場合:

ここに画像の説明を入力してください ここに画像の説明を入力してください

制御の流れは、ソースコードの依存関係と同じ方向に進みます。

実装関係の場合:

ここに画像の説明を入力してください ここに画像の説明を入力してください

制御の流れは通常、ソースコードの依存関係とは逆の方向に進みます。

これはあなたが本当にこれを見ていることを意味します:

ここに画像の説明を入力してください

制御のフローがプレゼンターからビューに到達することは決してないことがわかるはずです。

それはどうしてですか?どういう意味ですか?

これは、ビューに独自のスレッドがあること(これはそれほど珍しいことではありません)、または(@Euphoricが指摘しているように)ここに示されていない何かから制御の流れがビューに入ってくることを意味します。

同じスレッドの場合、Viewは、View-Modelを読み取る準備ができたことを認識します。しかし、それが事実であり、ビューがGUIである場合、ユーザーがDBを待機している間に画面を移動すると、画面の再描画に苦労します。

ビューに独自のスレッドがある場合、ビューには独自の制御フローがあります。つまり、これを実装するには、ViewがView-Modelをポーリングして変更を通知する必要があります。

プレゼンターはビューが存在することを知らず、ビューはプレゼンターが存在することを知らないため、お互いを呼び出すことはできません。彼らはお互いにイベントを投げることはできません。起こりうることは、プレゼンターがView-Modelに書き込み、ViewがView-Modelを読み取ることだけです。いつでもそのように感じる。

この図によると、ViewとPresenterが共有するのは、View-Modelの知識だけです。そして、それは単なるデータ構造です。そのため、動作を期待しないでください。

それは不可能に思えるかもしれませんが、View-Modelが複雑な場合でも機能させることができます。更新された小さなフィールドの1つは、ビューが変更を検出するためにポーリングする必要があるすべてのフィールドです。

もちろん、オブザーバーパターンの使用を主張したり、この問題をフレームワークによって隠したりすることもできますが、その必要はないことを理解してください。

ここに、制御の流れを説明するためのちょっとした楽しみがあります。

ここに画像の説明を入力してください

前に定義した方向に逆行するフローを見るときはいつでも、コールリターンが表示されていることに注意してください。このトリックは、ビューに到達するのに役立ちません。まあ、最初にControllerと呼ばれるものに戻らない限り。または、ビューに到達できるようにデザインを変更することもできます。また、これにより、データアクセスとそのインターフェイスのヨーヨー問題の始まりのように見えるものも修正されます。

ここで学ぶべき他の唯一のことは、ユースケースインターアクターが最後にプレゼンターを呼び出す限り、好きな順序でほとんど呼び出すことができるということです。


回答者に感謝します。クリーンアーキテクチャに関する他のさまざまな質問に対するあなたの答えを見てきました。たとえば、ビューモデル内で、変更があるかどうかを確認するために、ビューが常にフラグをチェックすることを提案していますか?その後、ビューはビューモデル全体を再表示する必要がありますか、またはネストされたフラグのセットを使用して、変更されたデータを示す必要がありますか?
Fearnbuster

ビューは常にポーリングする必要はありません。たとえば、web 1.0はユーザーがリロードをヒットしたときにのみポーリングします。常時ポーリングは、ユーザーの実際のニーズを考慮する必要がある設計上の決定です。可能だと言っているだけです。更新フィールドのポイントは、更新の検出を高速にすることです。ビューモデルが複雑な場合にのみ必要です。また、プレゼンターが更新の途中である間にビューが読み取った場合に何が起こるかを考慮してください。
candied_orange

さて、助けてくれてありがとう。このアーキテクチャを使用する場合/使用する場合、これは通常使用する手法ですか?
Fearnbuster

1
この回答が設計依存性とランタイム依存性をグループ化するという大きな間違いがあると思います。この2つは異なる場合があります。
陶酔

1
@Euphoricどうもありがとう。あなたが何かにソースコードの依存関係を持っていない場合、それが何であるか理解していないので、それに対するランタイム参照を何にも使用できないので、私はそれらを結び付けています。できることは、コレクションのように参照を保持することだけです。それが間違いである場合、私はそれを理解したいと思います。
candied_orange

2

MartinのClean ArchitectureとMVVMの両方を誤解していると思うので、この問題は混乱を招きすぎており、問題を適切に説明するには多くのテキストと時間がかかります。

最初に注意することは、投稿した図が不完全であることです。「ビジネスロジック」のみが表示されますが、実際には部品を正しい順序で移動させる「オーケストレーター」がありません。 ここに画像の説明を入力してください

オーケストレーターのコードは次のように簡単です

string Request(string request) // returns response
{
    Controller.Run(data);
    Presenter.Run();
    return View.Run();
}

クリーンアーキテクチャに関する彼の講演の1つで、これについてMartinが話すのを聞いたと思います。

もう1つ指摘することは、サイクルの不足に関するcandied_orangeの発言が間違っていることです。はい、サイクルのコードはコードのアーキテクチャに存在しません(存在するべきではありません)。しかし、実行時インスタンス間のサイクルは一般的であり、多くの場合、より単純な設計につながります。

MVVMの場合です。MVVMでは、ViewはViewModelに依存し、ViewModelはイベントを使用して、変更をViewに通知します。つまり、クラスの設計では、ViewクラスからModelクラスへの依存関係のみが存在しますが、実行時には、ViewインスタンスとViewModelインスタンスの間に周期的な依存関係があります。このため、ViewModelはいつ更新するかを判断するためのViewの方法を提供するため、オーケストレーターは必要ありません。このため、この図の「通知」では、直接の線ではなく「波線」の線を使用しています。これは、ViewがViewに依存することではなく、ViewがViewModelの変更を監視することを意味します。

ここに画像の説明を入力してください

MartinのClean Architectureからとるべき最も重要なことは、設計そのものではなく、依存関係の処理方法です。彼が講演で述べた重要なポイントの1つは、境界がある場合、その境界を越えるすべてのコード依存関係が単一の方向で境界を越えることです。図では、この境界は二重線で表されています。また、コードの依存関係の方向を修正するインターフェイス(InputBoundaryOutputBoundaryおよびDataAccessInterface)を介した依存関係の反転が多数あります。

対照的にViewModel、クリーンアーキテクチャでは、ロジックのない単なるDTOです。これは<DS>タグによって明らかになります。そして、これがorchestrator必要な理由ですView。いつロジックを実行するかわかりません。

実行時にダイアグラムを「フラット化」すると、次のようになります。

ここに画像の説明を入力してください

そのため、実行時に依存関係は「間違った」方向になりますが、それで問題ありません。

Clean Architectureについての彼の話を見て彼の推論をよりよく理解することをお勧めします。


あなたの「オーケストレーター」がプレゼンターを呼ぶべきではありません。ユースケースインタラクターがそれを行います。
candied_orange

@candied_orange確かに、それは間違いです。
陶酔

答えてくれてありがとう、いくつかの異なる意見を得るのは良いことです。両方の答えを支持しました。どちらかが、Robert Martinが彼のアーキテクチャのフォームを実装したコードベースをどこに持っているかを知っていますか?私は彼のFitNessプロジェクトを見ましたが、木の森を見ることができませんでした。また、私が投稿した画像はボブおじさんが彼の講演で常に使用している図であるにもかかわらず、実際にはあなたのアーキテクチャがどのように見えるかの単なる例であると推測するのは正しいですか?依存関係の流れが正しい限り、見た目は大きく異なりますか?
Fearnbuster

@Fearnbuster最後の質問に、はい。依存関係の方向は、構造よりも重要です。「クリーンアーキテクチャ」、「オニオンアーキテクチャ」、「ヘキサゴナルアーキテクチャ」は、実際には「依存関係を維持する」という同じ考え方の実装であると考えています。
陶酔

@Euphoric正直に言って、彼の本の別のイメージ(第8章の図8.2)で、彼は異なるように見えるアーキテクチャを示しているので、これが事実であると言えるでしょう。この図では、コントローラーは実際にはインターアクターとプレゼンターの間の仲介者です。インタラクターの出力境界もありません。Interactorはインターフェイスを介してリクエストを受信し、同じインターフェイスを介してレスポンスを返します(そのように機能する他のメカニズムは考えられないため、これは単純な関数の戻り値を介して行われると想定しています)。
Fearnbuster
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.