20

現在のプラクティス (少なくとも WPF と Silverlight を使用) では、ビュー モデルでコマンド バインディングを介してバインドされたビューが表示されるか、少なくともビュー モデルで処理されるビュー イベントが表示されます。ビュー モデルはビュー ステートをモデル化するだけでなく、ビュー (ユーザー) に応答するため、これはSRPに違反しているように見えます。他の人は、SRP に違反せずにビュー モデルを構築する方法を尋ねたり、実装がそうするかどうかを尋ねたりしました(これは MVC のコントローラーですが、ほぼ類似しています)。

では、現在の慣行は SRP に違反しているのでしょうか? それとも、「ビュー モデル」は本当に SRP に違反しないものの集まりなのでしょうか? これを少し理解するには、単一の責任とは何か、概念に複数の責任がある場合は、SRP に準拠して個々の責任が分割されているかを知る必要があるようです。わからない。

ウィキペディアのビューモデルの定義によると

[T]ViewModel は「View のモデル」であり、View と Model の間のデータ バインディングにも役立つ View の抽象化であることを意味します。

SRP にはこれで十分だと思われますが、後でエントリに次のように記載されています (強調を追加)。

[ViewModel] は、Model 情報を View 情報に変更し、View から Model にコマンドを渡すデータ バインダー/コンバーターとして機能します。

ビュー モデルの役割に関する Prism のブログ投稿で、著者は次のように述べています (繰り返しますが、私の強調です)

要するに、ビューモデルは次の複合体であるということです:

  • ビューの抽象化
  • コマンド
  • 値コンバーター
  • ビューステート

私はそこに多くの定義を見逃していると確信していますが、それらは次のカテゴリに分類されるようです:

  1. ビューステートのモデリングの単一の「あいまいな」責任 (つまり、状態とは どういう意味ですか)
  2. 複数の責任 (ビュー ステート、ユーザー インタラクション (つまりコマンド))
  3. 単一の特定の責任 (抽象化、状態、相互作用、変換) の複合体。したがって、「すべてのものを管理する」という単一の責任があります。

興味があれば、(2) は正しいと感じますが、一般的な実装に反しているように見えるので、私はこれを「気にします」。

4

4 に答える 4

11

マーティンが定義する単一の責任:

「クラスを変更する理由は 1 つ以上であってはなりません。」

ViewModel は、MVVM に関する限り、実際にはPresentation Modelの特殊な実装にすぎません。

そのため、プレゼンテーション モデルはUIの状態のみを表す必要があり、プレゼンター/コントローラーは常に UI とプレゼンテーション モデルの間でコマンドを仲介する必要があると主張することもできます。SRP が State と Commands を分割してこの考えに従う場合、コマンドを追加しても、状態を表すクラスに影響を与えるべきではありません。したがって、MVVM は SRP を壊します。

でも...

これはストローをつかんでいると思います。MVVM は、基本的に WPF/Silverlight (および現在はブラウザー クライアント) で使用されるかなり特殊な実装です。

パターンは、代替案がより面倒で保守しにくい場合に、設計をより単純にするように設計されています。MVVM は、プレゼンテーション テクノロジの非常に豊富なデータ バインディング機能を利用するように設計されているため、トレードオフの価値があります。

于 2011-08-23T17:05:21.263 に答える
6

いいえ!MVVM は SRP に違反していません (プログラマーは違反しています、笑)。

MVVM パターンを使用するために SRP を無視する必要があるという理由はありません。MVVM は、Model クラス、View-Model クラス、および View クラスが 1 つしかないという意味ではありません。確かに、View Class が 1 つしかない場合は、単純な画面を 1 つしか表示できません。

ビュー層にあるこれらのクラスは、1 つのことを担当する必要があります。する、決定する、または含む。ビューは、ユーザーの相互作用の特定の部分を実行する仕事をするいくつかのサブビューで構成できます。表示グリッドがあり、グリッド内の項目を編集でき、「保存」ボタンがある基本的なフォームを考えてみましょう。

メイン ビューは、他の 2 つのビューのコンテナーになります。データグリッド (ユーザー コントロールなど) とコマンド コントロール。次に、データグリッドは、データをレンダリングする適切な子ビューを選択する責任があります。本質的には、データバインドするコンテナーです。項目を編集するビューはデータグリッドの子ビューであり、これはメイン ビューの子です。最後に、コマンド コントロールは一連のボタン (この場合は 1 つ) であり、ユーザーがコマンドを発行したことを示す信号を出すことだけを担当します。

このように、編集ビュー (DataGrid によって使用される) は、それを使用するものにとらわれず、1 つの責任を持ちます。コマンドコントロールと同じです。同様に、DataGrid は誰がそれを使用するかを気にせず、編集ビュー (子) を含めることができることだけを気にします。素敵な SRP があります。

Views (および子) に一致する ViewModels も、1 つのことを担当します。編集ビュー モデルは、編集ビューがバインドされるコンテナーです。表示/編集できるデータ フィールドが含まれているだけです。プロパティの 1 つが変更されたときのシグナリング以外は気にしません。コマンド ボタン ビュー モデルは、処理を行うクラスです。コマンドはボタンにバインドされており、ユーザーがクリックした内容に基づいて機能します。その作業を行うには、ViewModel の他の部分にアクセスする必要があります。

メイン ページの View Model には、他の子ビューが含まれています。唯一の責任は、イニシャライザとして、必要なすべての ViewModel インスタンスを作成し、コンストラクタ パラメータを他の ViewModel インスタンスに渡すことです (たとえば、コマンド ボタン ビュー モデルを使用して、その作業のためにデータを取得する場所を認識します)。

大きな View がバインドされる単一の ViewModel に、たくさんの機能を詰め込むのは自然なことです。しかし、そうである必要はなく、SRP は MVVM で維持できます。

MVVM の主な目標は、テスト可能な設計を可能にすることです。モデル層は独立してテストでき、モデル内のすべてのクラスは SRP に簡単に従うことができます。ViewModel は、ビューを必要とせずにテストできます。ViewModel で SRP を考えるのは難しくなりますが、確かに実行可能です。懸念事項が 1 つだけになるように、クラスを分割することを忘れないでください。View は、ViewModel の一部にバインドされています。運が良ければ、ViewModel のテストにより、View のスナップが非常に簡単になります。各ビューレットを SRP に準拠させて、より大きなコングロマリット ビュー (コンテナー) の一部にすることができることを覚えておいてください。

TL;DR? あなたの質問に直接答えるために、View は SRP を壊さないクラスのコレクションです。したがって、ViewModel が View(s) から抽象化される (View-First) 場合、それらは適切な SRP に準拠するクラスのコレクションでもあります。

于 2011-08-23T21:39:05.940 に答える
6

私は、MVVM に関する現在のプラクティスの多くが (少なくとも) SPR に違反していると考えています。これは、コントローラを MVVM に戻すだけですべての問題がきれいに解決される、もう 1 つの状況です。私はそれをMVCVMと呼んでいます:)

最近のすべてのプロジェクトで成功しているパターンは、コントローラーのみをモジュールに登録し、起動時にそれらを初期化することです。コントローラーは非常に軽量/スリムで、メッセージをリッスンまたは送信するアプリの存続期間中、ぶらぶらする必要がある唯一のものです。初期化メソッドでは、所有する必要があるもの (ビューやビューモデルなど) を登録します。この軽量なメモリ内ロジックのみのパターンは、よりスリムなアプリにもなります (たとえば、WP7 の方が適しています)。

あなたが見つけたように、VM を使用するだけの問題は、最終的には、ビュー、コマンド、または自尊心のある ViewModel が関与してはならないその他のものについて知る必要がある場合に遭遇することです!

私たちが従う基本的なルールは次のとおりです。

  • コントローラーはイベントに基づいて決定を下します
  • コントローラーはデータを取得し、適切なビュー モデル プロパティに配置します。
  • コントローラーは、ビュー モデルの ICommand プロパティを設定して、イベントを傍受します
  • コントローラーはビューを表示します (他の場所で暗示されていなければ)
  • ビューモデルは「ばか」です。バインド用のホールド データのみ
  • ビューは、特定の形式のデータを表示することを認識していますが、それがどこから来たのかはわかりません

最後の 2 つのポイントは、決して破ってはならないものです。

コントローラを MVVM ミックスに戻すだけで、見つかったすべての問題が解決するようです。MVVM は良いことですが、なぜコントローラーが含まれていないのでしょうか? (しかし、これはもちろん私の意見です):)

于 2011-08-24T09:51:31.233 に答える
2

要するに、ビュー モデルは次の複合体であるということです。

  • ビューの抽象化
  • コマンド
  • 値コンバーター
  • ビューステート

最初の 2 つの項目を分けた理由がわかりません。コマンドはビューの一部です。

残りについては - あなたは正しいです。ある場合には。私は、値の変換とビュー ステートの維持のタスクが非常に複雑で、単一のビュー モデル クラスですべてを実行するのは理にかなっていないアプリケーションを構築し、それらを VM と相互運用する個別のクラスに分割しました。

そう?

于 2011-08-23T17:24:58.140 に答える