MVVMの使用はどのような条件下で適切ですか?


47

Model View View-Modelは、イベント駆動型プログラミング、特にXAMLおよび.NET言語を使用する.NETプラットフォーム上のWindows Presentation Foundation(WPF)およびSilverlightをサポートするUI開発プラットフォームをターゲットとしてMicrosoftによって開発されました。それ以来、Angular、Knockout、ExtJSなどの多くのJavascriptフレームワークがこのパターンを採用しています。

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

ほとんどのソフトウェアパターンと同様に、MVVMには適切な用途と悪用があります。MVVMの使用はどのような条件下で適切ですか?いつお勧めしませんか?


4
悲しいことに、現実の世界には、正確に定義することができない多くの複雑さがあります。ある特定のポイントを超えて、それが何に依存しているかを言うことはできません-それぞれの特別なケースはまれですが、可能な特別なケースの範囲は無限であり、それらが発生するまですべて見つけることはできません。ある時点で、パターンなどの基本的な目標を認識し、それらの目標がいつ達成されないかを認識できるようにする必要があります。完璧なスキームもありませんが、経験が役立ちます。
Steve314

1
@ Steve314それは議論の余地があります。これは、MVVMが美しいデザインの邪魔にならないようにし、間違いなく製品の出荷を止めさせないでください。
ルークププレ

@ルーク-それは本当ですが、私のポイントは、美しいデザインがあなたの製品の出荷を止めさせてはいけないということでもありました。適切なデザインパターンは、適切に使用する限り、そして現実世界がそれ自体で動作する限りにおいてのみ有効です。
Steve314 14年

@ Steve314ロジャーそれ。
ルークピュレット14年

回答:


19

MVVMは、高忠実度UIを使用した複雑なユーザーインタラクションが必要な場所(つまり、WPF)で使用することを目的としています。

MVVMは、ユーザーエクスペリエンス(UXi)開発者がより「伝統的な」開発者とは異なる要件(ビジネスロジックやバックエンド開発)。MVVMのView-Modelは「基本的にステロイドの値コンバーター」です。つまり、View-Modelは、データオブジェクトを簡単に管理および使用できるようにモデルからデータオブジェクトを公開する役割を果たします。この点で、View-ModelはViewよりも多くのモデルであり、Viewの表示ロジックのすべてではなくてもほとんどを処理します。

MVVMは、WPFの特定の機能を使用して、Viewレイヤーから事実上すべての「コードビハインド」を削除することにより、Viewレイヤーの開発とパターンの残りの部分との分離を容易にするように設計されました。インタラクティブデザイナーにViewコードの記述を要求する代わりに、ネイティブWPFマークアップ言語XAMLを使用して、ViewDeveloperへのバインディングを作成できます。ViewModelは、アプリケーション開発者が作成および管理します。この役割の分離により、インタラクティブデザイナーはプログラミングやビジネスロジックではなくUXのニーズに集中できるようになり、アプリケーションのレイヤーを複数のワークストリームで開発できるようになります。

この種のリッチな対話が不要なUIの場合、MVVMは過剰な場合があります。MVPはより自然な選択かもしれません。Webアプリケーションの場合、MVCの方が適しています。決して大きくなることのない非常に小さなアプリケーション(小さなWinformsユーティリティなど)の場合、分離コードが適切です。


1
数年先に進みましょう。ノックアウトについてどう思いますか?私はWPFから来た後に使用しましたが、WPFに比べてどれだけ軽量であるかを知り、私にとって多くの「やり過ぎ」の側面を取り除いて喜んで驚きました。
J Trana

15

MVVMがトラップになる場合があります。私の経験から、タスク指向のUIよりもCRUDのようなアプリケーション(データよりもフォーム)の方が有利です。私はそれがアプリケーションのバックエンド/その他のレイヤーの悪いアーキテクチャを暗示していると言っているわけではありませんが、多くのMVVMアプリケーションが「DDDライト」アーキテクチャを備えているのを見てきました。バインディングが非常に簡単で、POCO / Anemicドメインオブジェクトを使用してORMとMVVM / Bindingを使用してアプリケーションをセットアップするのが非常に簡単であるため、なぜか正確にはわからない。


10
開発者の想像力の欠如は、パターンの失敗ではありません。タスク指向のViewModelは非常に簡単に作成できます。
ショーン

6
これらの頭字語の一部を拡張することもできます。
ローマンライナー14年

13

MVVMは、設計が不十分なデータバインディングレイヤーのバンドエイドです。特に、WPF / XAMLのデータバインディングの制限のため、WPF / silverlight / WP7の世界で多くの使用が見られています。

これからは、WPF / XAMLについて話していると仮定します。これにより、物事がより明確になるからです。MVVMがWPF / XAMLで解決するために設定した欠点のいくつかを見てみましょう。

データ形状とUI形状

MVVMの「VM」は、C#で定義されたオブジェクトのセットを作成し、XAMLで定義されたプレゼンテーションオブジェクトのセットにマップします。これらのC#オブジェクトは通常、プレゼンテーションオブジェクトのDataContextプロパティを介してXAMLに接続されます。

その結果、viewmodelオブジェクトグラフは、アプリケーションのプレゼンテーションオブジェクトグラフにマッピングする必要があります。それは、マッピングが1対1である必要があるということではありませんが、リストコントロールがウィンドウコントロールに含まれている場合、ウィンドウのDataContextオブジェクトからそのリストのデータを記述するオブジェクトに取得する方法が必要です。

ビューモデルオブジェクトグラフは、UIオブジェクトグラフからモデルオブジェクトグラフを正常に分離しますが、構築および維持する必要がある追加のビューモデルレイヤーを犠牲にします。

画面Aから画面Bにデータを移動する場合は、ビューモデルをいじる必要があります。ビジネスマンの心では、これはUIの変更です。それはすべきである XAMLの世界では、純粋に場所を取ります。悲しいことに、それはめったにできません。さらに悪いことに、ビューモデルがどのように構造化されているか、データがどの程度アクティブに変更されるかに応じて、この変更を実現するためにかなりのデータの再ルーティングが必要になる場合があります。

非表現的なデータバインディングの回避

WPF / XAMLバインディングは表現力が不十分です。基本的に、オブジェクトに到達する方法、通過するプロパティパス、およびプレゼンテーションオブジェクトが必要とするものにデータプロパティの値を適合させるためのコンバータをバインドする方法を提供します。

C#のプロパティをそれより複雑なものにバインドする必要がある場合、基本的には運が悪いです。True / FalseをVisible / Collapsedに変換するバインディングコンバーターのないWPFアプリを見たことはありません。多くのWPFアプリには、NegatingVisibilityConverterと呼ばれる、極性を反転させるようなものが含まれる傾向があります。これにより、警告音が鳴ります。

MVVMは、この制限を緩和するために使用できるC#コードを構造化するためのガイドラインを提供します。SomeButtonVisibilityと呼ばれるビューモデルのプロパティを公開し、そのボタンの可視性にバインドすることができます。XAMLは素晴らしく、きれいになりました...しかし、あなたは店員になりました。今、UIが進化するとき、2つの場所(UIとC#のコード)でバインディングを公開+更新する必要があります。同じボタンを別の画面に配置する必要がある場合は、その画面からアクセスできるビューモデルで同様のプロパティを公開する必要があります。さらに悪いことに、XAMLを見て、ボタンがいつ表示されるかを確認することはできません。バインディングが少し自明ではなくなるとすぐに、C#コードで検出作業を行う必要があります。

データへのアクセスは積極的にスコープされます

通常、データはDataContextプロパティを介してUIに入力されるため、アプリ全体でグローバルデータまたはセッションデータを一貫して表すことは困難です。

「現在ログインしているユーザー」というアイデアは素晴らしい例です。これは、多くの場合、アプリのインスタンス内で本当にグローバルなものです。WPF / XAMLでは、現在のユーザーに一貫した方法でグローバルアクセスを保証することは非常に困難です。

私がやりたいのは、データバインディングで「CurrentUser」という単語を自由に使用して、現在ログインしているユーザーを指すことです。代わりに、すべての DataContextが現在のユーザーオブジェクトに到達する方法を提供することを確認する必要があります。MVVMはこれに対応できますが、ビューモデルはすべてこのグローバルデータへのアクセスを提供する必要があるため、混乱するでしょう。

MVVMが倒れる例

ユーザーのリストがあるとします。現在ログインしているユーザーが管理者である場合にのみ、各ユーザーの横に「ユーザーの削除」ボタンを表示します。また、ユーザーは自分自身を削除することはできません。

モデルオブジェクトは、現在ログインしているユーザーを認識してはなりません。データベースのユーザーレコードを表すだけですが、何らかの理由で、現在ログインしているユーザーは、リスト行内のデータバインディングに公開する必要があります。MVVMは、現在ログインしているユーザーとそのリスト行で表されるユーザーを構成する各リスト行のビューモデルオブジェクトを作成し、そのビューモデルオブジェクトで「DeleteButtonVisibility」または「CanDelete」というプロパティを公開する必要があることを指示しますコンバーターのバインドについて)。

このオブジェクトは、他のほとんどの点でユーザーオブジェクトに非常によく似ています。ユーザーモデルオブジェクトのすべてのプロパティを反映し、データの変更に応じてそのデータを更新する必要がある場合があります。これは本当に気分が悪いと感じます-繰り返しますが、MVVMは、このユーザーに似たオブジェクトを維持することを強制することで、あなたを店員にします。

考慮してください。おそらく、データベース、モデル、ビューでユーザーのプロパティを表す必要があります。自分とデータベースの間にAPIがある場合、さらに悪いことになります。それらは、データベース、APIサーバー、APIクライアント、モデル、およびビューに表示されます。プロパティが追加または変更されるたびにタッチする必要がある別のレイヤーを追加するデザインパターンを採用することを本当にためらいます。

さらに悪いことに、このレイヤーは、データモデルの複雑さではなく、UIの複雑さに合わせて調整されます。多くの場合、同じデータが多くの場所とUIに表示されます。これにより、レイヤーが追加されるだけでなく、多くの余分な表面積を持つレイヤーが追加されます。

物事はどうだったか

上記のケースでは、私は言いたいです:

<Button Visibility="{CurrentUser.IsAdmin && CurrentUser.Id != Id}" ... />

CurrentUserは、アプリ内のすべてのXAMLにグローバルに公開されます。Idは、リスト行のDataContextのプロパティを参照します。可視性はブール値から自動的に変換されます。Id、CurrentUser.IsAdmin、CurrentUser、またはCurrentUser.Idを更新すると、このボタンの可視性が更新されます。簡単です。

代わりに、WPF / XAMLはユーザーに完全な混乱を作成させる。私の知る限り、一部の創造的なブロガーはその混乱に名前を平手打ちし、その名前はMVVMでした。だまされてはいけません。GoFのデザインパターンと同じクラスではありません。これは、いデータバインディングシステムを回避するためのugいハックです。

(このアプローチは、さらに読みたい場合に「機能的リアクティブプログラミング」と呼ばれることもあります)。

結論として

WPF / XAMLで作業する必要がある場合、MVVMはお勧めしません。

上記の「方法」の例のようにコードを構造化します。モデルは、ビューに直接公開され、複雑なデータバインディング式+柔軟な値強制を使用します。より読みやすく、書きやすく、保守しやすい方法です。

MVVMは、より冗長で保守性の低い方法でコードを構造化するよう指示します。

MVVMの代わりに、優れたエクスペリエンスに近づけるためにいくつかのものを構築します。グローバル状態を一貫してUIに公開するための規則を開発します。より複雑なバインディング式を表現できるバインディングコンバータ、MultiBindingなどからツールを作成します。バインディングコンバーターのライブラリを作成して、一般的な強制の場合の痛みを軽減します。

さらに良いこと-XAMLをより表現力豊かなものに置き換えます。XAMLは、C#オブジェクトをインスタンス化するための非常にシンプルなXML形式です。表現力豊かなバリアントを作成するのは難しくありません。

私の他の推奨事項:この種の妥協を強制するツールキットを使用しないでください。問題領域に集中するのではなく、MVVMのようなくだらないものにあなたを押しやることで、最終製品の品質を損ないます。


23
-1:これらのポイントのほとんどは浅く、特定のWPF機能を使用することで問題のほとんどを克服できます。MVPパターンのポイントを完全に見逃していると思います。
ファルコン

14
例:「ここには大きな欠点があります。データがそのように機能しないことがよくあります。データの形状はUIの形状とは非常に異なる場合があります。」正しい-だから、そもそもViewModelがあるのです。
ファルコン

8
これは少し多すぎるFUDです。まず、WPFアセンブリにはBooleanToVisibilityConverterがあるため、作成する必要はありません。たとえば、セッションなどからの静的な情報に本当にバインドしたい場合は、x:Staticを使用できます。RelativeSourceなどを使用して、上位のVM情報にアクセスする可能性が高くなります。次に、テンプレートとスタイルを使用して行う多くのことで、説明している問題を解決します。その後、マルチバインディングを実行できます。リストは続く
...-flq

8
質問の目的の一部がこの回答で失われ、WPF / SLで暴言になったと思います。その答えは主に、パターンが提供する役割と原則を議論することではなく、特定の実装を作成するのが難しいことで構成されています。また、正直に言うと、この回答で言及されている多くのことは、MVVMが試みられた下線を引く技術に関するより多くの知識を必要とします。上記の問題の多くには解決策があります。この答えでは、ViewModelの役割は忘れられているようです。
ケリーソマーズ

8
これは、民主主義が最悪の形態の政府であるように思われます(もちろん、以前のすべての形態を除く)、一種の声明です。もちろん、WPFには問題がありますが、それは間違いなくwinformsに勝るものです。MVVMを使用したWPFは、MVVMを使用しないよりも、簡単なアプリよりも大きなものであれば、間違いなく簡単です。
ジョエルバルソッティ

8

私はMVVMが本当に好きで、その挑戦がやる気を起こさせ、多くの利点を見出していますが、...

  1. パフォーマンスを維持しながら多くのカスタム動作を追加するために多くのUI /相互作用コードを必要とするアプリケーションまたはゲームの場合-少し汚れたMVVMを使用する方が良い場合が多い-それが有用であるか、またはコードの相互作用中心領域。コントロールを作成し、別の親コントロール間で移動するか、それ以外の場合はキャッシュする場合...

  2. かなり急な学習曲線を持っているので、時間がない限り、WPF / SLで多くの開発を計画し、デザイナーにBlendを熟練させ、UIのテストコードを書く必要性を感じます。プロジェクト-それは報われないかもしれません。

  3. Blendを知っているデザイナーはそれほど多くありません。すべてのプロジェクトがプレゼンテーション層で自動テストに集中する価値があるわけではありません。とにかく手動でテストする必要があり、VMをテストするのではなく最も重要なバグを見つける方法です。

  4. それは本当に投資です。最初にWPF / SLとXAMLの基本を理解してから、バインディングを適切に行う方法を理解し、vmsに何らかの順序で接続し、コマンドを正しく取得し、ほとんどの場合フレームワークを選択する必要がありますライセンスが原因で問題が発生する場合、コードに効率的にコードライブラリを構築します。ただし、プラットフォームが常にバインディングとうまく機能せず、必要な動作を実現する動作のライブラリを構築する必要があることがわかります。

全体的に-すべてのハードルを克服し、パターンにかなり習熟すると、明確さ、保守性、および自慢の権利がすべて返されますか?:)


私はそれが急な学習曲線を持っていることに同意しません。午後にMMVMについて十分に学習し、生産性を高めることができます。また、ブレンドを知ることはMVVMの要件ではありません。
ショーン

6
@Sean、申し訳ありませんが、私は3日目にまだ苦労しています:(おそらく、ダイアログボックスを開く、モデルのツリービューで選択したアイテムを設定するなどの「複雑な」ことをしようとしているためです...
ベンジョー

8

私は長年にわたり、MVVM上で取引システムなどの巨大なアプリケーションを構築しているWPF / Silverlightプログラマーです。

私にとっては、年が経つにつれて、厳格なMVVMが時間を消費し、費用がかかることを学びました。厳密には、「コードビハインドなし」などのルールを意味します。

コードビハインドを持たないことは、最も基本的なフォーム/データベースアプリ以外では不可能です。

設計者は、1日目に標準コントロールでは不可能な何かを指定するため、MVVMでの作業中に相互作用パラダイムをサポートするには、一連のカスタムコントロールを構築するか、既存のコントロールをラップする必要があります。

数学、慣性、ジェスチャなどを使用して、あらゆる種類のswish UIコントロールとそのハードワークを記述しました。

しかし、これはすべてコードビハインドであり、ビューには含まれていません。ボタンのクリック、スクロール、ドラッグなどを処理する必要がありますが、そのすべてが一連のコントロールにうまくまとめられているため、このコードビハインドがうまくいきます。

ビューのために一連のコントロールを構築するのではなく、ビューにコードビハインドと巧妙なUIを単に記述する方が簡単です。

MVVMの目標は、アプリケーション/ビジネスロジックをUIロジックから分離することです。バインディングシステムとMVVMは、これを行うための良い方法です。

1つの机のXAMLデザイナー、もう1つの机のC#プログラマー、VSのもう1つのブレンドで作業するなど、宣伝されている他の目標は誤りです。

UIを迅速に再設計できることも誤解です。それは決して起こらない、その時期尚早な最適化。大規模な手直しには、ビューモデルに対して多くの作業が必要です。微調整は1つのことですが、UIをすばやくオーバーホールすることはできません。ビューモデルは相互作用のパラダイムに適合している必要があるため、カップリングは実現するよりも緊密です。

私にとっては、MVVMを使用してアプリケーションロジックを分離します(通常はテスト可能なコントローラーとロジックレスビューモデルのセットを使用します)が、UIをセクシーに見せて動作させるために必要なコードやトリックは何でもありません。汗をかきます。

それ以外の場合、MVVMをどのようにアライズするかというアイデアがあまりにも気が遠くなるだけで、デザインやクールなアニメーションなどを支配することになります。

MVVMは、人生のほとんどのものと同様に 2つの両極端の中間にあるスイートスポットを持っています。

ソフトウェア設計で最も重要なことは、製品を早期に出荷し、使用されている機能、UIが適切に機能していることを確認し、誰も使用していない製品の美しいコードを作成しないことです。


7

アプリケーションが大量のデータにリアルタイムでバインドする必要がある場合、MVVMはプロセスを遅くする抽象化を導入しているため、実際に邪魔になることがあります。現在、エンジンはそれほど効率的ではありません。機能拡張は進行中ですが。

MVVMは、現状では、考慮する必要がある方程式の唯一の部分ではありません。切断されたViewModel間で通信できるように、MediatorパターンなどのインフラストラクチャでPure MVVMをサポートする必要があります。

上記のbluczの意見にもかかわらず、MVVMはGoFパターンのラインにあります。パターンを見ると、MVVMはModel View Passive Presenterパターンと同等であり、MVVMとほぼ同時に表示されます。MVVMの複雑さについて不満を言う人が多いのは、MVVMを使用して設計する方法を理解していないためです。

MVVMで問題を発見した別の領域は、それをサポートするように設計されていないサードパーティテクノロジ(MS DynamicsのUIIフレームワークなど)を組み込む必要がある場合です。MVVMを使用するだけで、他の技術を「ハッキング」する苦労に見合う価値があるかどうかを自問する必要があります。

Win FormsのようなものをWPFソリューションに混ぜ合わせている場合、ソリューションのその部分はおそらくMVVMにも適していません。これにより、MVVMが適用されない場所に関するいくつかの領域のアイデアが得られることを願っています。


4

次の場合、MVVMを使用しても意味がありません。

  • WPFまたはSilverlightを使用していない
  • コンセプトをテストしています

それでおしまい。別のプロジェクトで何かをテストまたはデバッグしている場合を除き、WPF / Silverlightで作業するときにMVVMを使用しない理由を本当に考えることはできません。XAMLバインディングが機能するため、デザインパターンはWPF / Silverlightの開発に理想的です。

MVVMの全体的なポイントは、アプリケーション全体がViewModelsで実行されることであり、Viewsは、ユーザーがViewModelsと対話するために使用できるきれいなレイヤーにすぎません。ボタンをクリックすると、実際にはViewModelメソッドが実行されます。ページを変更する場合、実際にはViewModelのCurrentPageプロパティを変更しています。

MVVMの使用方法はプロジェクトのサイズと必要なものに応じて異なりますが、すべてのWPF / Silverlight開発、小規模で単純な単一ページプロジェクトにもMVVMを使用します。MVVMを使用せずに小さなアプリを作成したとき、後悔しました(後で更新を追加するときにMVVMを使用するようにリファクタリングされました)。


3

MVVMに変換しようとしてコードビハインドのプロジェクトでクライアントのためにいくつかの仕事をしましたが、それは巨大な混乱でした。それは、すべての分離コードプロジェクトが混乱していると言うことではありません。ビューはBlendをエラーまたはクラッシュさせ、デザイナーに問題を引き起こします。

私はRoRに手を出し、ASP.NET Webformsで何もすることをほとんどスキップしましたが、ASP.NET MVCが登場したとき、できる限り多くのことを学ぼうとしました。 。別のパターンですが、SL / MVVM開発のIn Actionブックから学んだことの多くを使用しています。

Silverlightで作業を始めたとき、私はそれがどれほど裸であるかに驚きました。これは、MVVMの学習をあきらめる人々の問題と考えています。

優れたMVVM-Lightから始めて、パターンを完全に把握できるようにしました。その後、Caliburn Microとの作業を開始し、その後ライトが点灯しました。私にとって、Caliburn MicroはASP.NET MVC over ASP.NET Webformsを使用するようなものです。そのため、小さなサンプルアプリケーションであっても、プロジェクトNuGet CMを作成し、実行しています。私はViewModelの最初のアプローチに従い、ビューをバカにして、Blendでの作業を簡単にします。私のVMはテストに参加でき、CMを使用すると複雑な画面レイアウトを簡単に調整できます。


2

この代替案をチェックしてみてください。このオプションは、データバインディング、データテンプレート、およびMVVMのWPF方法を回避します。このオプションは、従来のシンプルで信頼できるWinForms designer.csアプローチに似ています。

WPFコンポジット

http://wpfcomposites.codeplex.com/

ここでは、WPFの簡潔なC#コードビハインドは、グリッドベースのコンポジットを介してUIの上に単純なマトリックスをオーバーレイすることによって生成されます。最新のXAML UIにいくつかのテキストラベルと写真のリストボックスのみが含まれている場合、これをコードの単純な行で定義できないのはなぜですか:grid.AddText(guid、x座標、y座標)?これはキャンバス上ではなく、グリッド、ドックパネルなどのWPFコンテナ内にあります。WPFは非常に強力です。このアプローチはこれを活用するだけです。

開発者は通常、マトリックスとインデックスを気にしません。データ転送オブジェクト(DTO)またはPOCOのGUIDで定義された粒度の粗いコンテナレベルから始めて、潜在的な行と列の粒度の細かいマトリックスでこれらのキー付きコンテナを補完しますか?

上記のcodeplexプロジェクトでは、ListBoxコントロールから開始することでこのアプローチを導入していますが、すべてのWPF複合コントロールをカバーするように拡張されています。たとえば、各listboxitemはGUIDで追加された複合(複合はクラスに1対1で結び付けられます)であり、この項目内には子UI要素(子がプロパティに1対1で結び付けられます)のグリッドがありますクラス内)は、コードビハインドを介して自由に追加できます。子はテキストブロックまたは画像である可能性があります。

アイデアは、データテンプレートの代わりに、インデックスと明確に定義されたUI要素構造(ベースとなるPresentationFramework.Aeroテーマリストボックスを強制する)を活用することです。この新しいアプローチは、できることを意図的に制限しますが、そうすることで、簡潔で堅牢なC#コードビハインドが得られ、直感的です。スクロールバーをスタイリングするためのコントロールテンプレートソリューションを探したり、単純なタスクのために複数のデータテンプレートでソリューションを散らかしたりする必要はありません。


-2

MVVMは、主に私が使用しているUIフレームワークに基づいています。そのため、WPFやSilverlightのような、データコンテキストへのバインドに基づいたパラダイムを持つものでは、そのデータコンテキストは常にビューモデルと呼ばれます。

したがって、私にとっての質問は、このコントロール/ウィンドウ/アプリケーションのビューモデルである大きな太った別個のクラスをいつ構築し、すでに構築されたオブジェクトをいつ使用できるかです。

したがって、抽象化のレイヤーを追加することについての古典的な質問があります。VMはプロジェクトに重量、慣性、構造を追加します。構築は簡単になりますが、変更は難しく、構築は長くなります。これらはどれも容易に定量化できません。

簡単な答えとして、MVVMはコマンドラインアプリやWebサービスには適していません:)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.