1. ホーム
  2. c#

[解決済み] なぜMVVMを使うのか?

2023-07-01 20:13:09

質問

さて、私はMVVMパターンについて調べているのですが、以前調べようとするたびに、いろいろな理由で断念していました。

  1. 不要な余分な長ったらしいコーディング
  2. コーダーにとって明白な利点がない (私のオフィスにはデザイナーがいない。現在、自分だけがすぐに別のコーダーになる)
  3. 良いプラクティスのリソース/ドキュメントがあまりない! (少なくとも見つけるのは難しい)
  4. これが有利になるようなシナリオは一つも思いつかない。

私はまだそれをあきらめようとしていて、誰かが上記の理由に答えるかどうか尋ねてみようと思いました。

正直なところ、シングル/パートナーでのコーディングにこれを使用する利点が見当たりません。たとえ 10 のウィンドウを持つ複雑なプロジェクトであってもです。私にとっては、DataSet は十分なビューであり、次のようなバインディングです。 ブレント 次の 質問

MVVMパターンを使用することで、XAMLのデータバインディングと比較して、時間を節約できる例を示してください。

私のバインディングの100%は、現在XAMLで行われます。したがって、私は、私が書き、依存する必要がある背後にある余分なコードであるため、VMのポイントがわからない。

EDITです。

午後からMVVMについて調べていたら、ようやくその本当の良さを実感できるものを見つけました。 答え .

どのように解決するのですか?

概要

  • すべてのパターンの使用は状況に応じて行われ、利点は (もしあれば) 常に複雑さを軽減することにあります。
  • MVVMは、GUIアプリケーションのクラス間で責任を分散させる方法を教えてくれます。
  • ViewModel は Model からのデータを View に適合する形式に投影します。
  • 些細なプロジェクトでは、MVVMは不要です。Viewだけを使用すれば十分です。
  • 単純なプロジェクトでは、ViewModel/Modelの分割は不要で、ModelとViewを使うだけで十分な場合があります。
  • ModelとViewModelは最初から存在する必要はなく、必要な時に導入すればよい。

パターンを使うべきとき、避けるべきとき

十分にシンプルなアプリケーションでは、すべてのデザインパターンは過剰なまでに使われます。押されると "Hello world" と表示される単一のボタンを表示する GUI アプリケーションを書くとします。この場合、MVC、MVP、MVVM などのデザイン パターンはすべて、多くの複雑さを追加しますが、何の価値も追加しません。

一般的に、なんとなく合っているからという理由でデザインパターンを導入するのは、常に悪い判断です。デザインパターンは、全体の複雑さを直接減らすか、見慣れない複雑さを見慣れた複雑さに置き換えることによって、複雑さを減らすために使用されるべきです。 もしデザインパターンがこれらの2つの方法のどちらかで複雑さを減らすことができないのであれば、それを使ってはいけません。

見慣れた複雑さと見慣れない複雑さを説明するために、次の2つの文字列を例に挙げてみましょう。

  • D.€|Ré%dfà?c"
  • "CorrectHorseBatteryStaple"。

2 番目の文字列は最初の文字列の 2 倍の長さですが、最初の文字列よりも読みやすく、速く書け、覚えやすいのは、すべてそれがより親しみやすいからです。同じことが、コード内の見慣れたパターンにも当てはまります。

この問題は、親しみやすさが読者に依存することを考慮すると、別の次元になります。ある読者は、3.14159265358979323846264338327950" が上記のパスワードのいずれかよりも覚えやすいと感じるでしょう。そうでない方もいらっしゃるでしょう。ですから、MVVMのフレーバーを使用したい場合は、使用している特定の言語とフレームワークで最も一般的なフォームを反映したものを使用するようにしてください。

MVVM

とはいえ、例によってMVVMのトピックに飛び込んでみましょう。MVVM は、GUI アプリケーションのクラス間 (またはレイヤー間 - これについては後で説明します) で、クラスの数を少なくし、クラスごとの責務の数を少なくし、よく定義することを目標に、責務を分散する方法を教えてくれます。

適切な」MVVMは、少なくとも中程度の複雑なアプリケーションを想定しており、どこかから取得したデータを扱います。データベース、ファイル、Webサービス、または無数の他のソースからデータを取得することができます。

この例では、2つのクラス ViewModel は存在しないが ViewModel . また Model は csv ファイルをラップし、 起動時に読み込み、アプリケーションが終了したときにユーザがデータに加えた すべての変更とともに保存します。また View からのデータを表示する Window クラスです。 Model のデータをテーブルに表示し、ユーザがそのデータを編集できるようにする Window クラスです。csvのコンテンツは、なんとなくこんな感じでしょうか。

ID, Name, Price
1, Stick, 5$
2, Big Box, 10$
3, Wheel, 20$
4, Bottle, 3$

新しい要件です。価格をユーロで表示する

今、私たちはアプリケーションに変更を加えるよう求められています。データは 2 次元グリッドで構成され、すでに USD の価格を含む "price" 列があります。事前に定義された為替レートに基づいて、米ドル建てに加えてユーロ建ての価格を表示する新しい列を追加する必要があります。他のアプリケーションが同じファイルで動作し、これらの他のアプリケーションは私たちのコントロール下にないため、csv ファイルの形式は変更してはいけません。

可能な解決策は、新しいカラムを単に Model クラスに追加することです。これは最良の解決策ではありません。 Model は csv に公開するすべてのデータを保存し、csv に新しいユーロ価格のカラムを作りたくないからです。そのため Model への変更は非自明なことであり、また、Model クラスが行うことを記述するのは難しく、それは コードの匂い .

また、この変更は View で変更することもできますが、現在のアプリケーションでは、データバインディングを使って Model クラスによって提供されるデータを直接表示するためにデータバインディングを使用しています。GUI フレームワークでは、テーブルがデータ ソースにデータ バインドされている場合、テーブルに追加の計算カラムを導入することができないため、テーブルの クラスを大幅に変更する必要があります。 View を大幅に変更する必要があり、これを実現するために View はもっと複雑になります。

ViewModel の紹介

は存在しません。 ViewModel が存在しないため、アプリケーションでは Model は Csv が必要とする方法でデータを表示し、それはまた View が必要とする方法です。このように ViewModel を挟むことは、目的もなく複雑さを増していたことでしょう。しかし、今では Model がデータを提示しなくなったので View が必要とする方法でデータを表示することができなくなったので、私たちは ViewModel . ViewModel のデータを投影します。 Model を投影するようにします。 View はシンプルにすることができます。 以前は View クラスをサブスクライブしていました。 Model クラスをサブスクライブしています。ここで、新しい ViewModel クラスのサブスクライブ先が Model クラスを購読し Model のデータを View - に、価格をユーロで表示するカラムを追加しています。そのため View はもはや Model を知らないので、今は ViewModel という点から View と同じに見えますが Model は以前と同じように見えますが、公開されたデータには新しい読み取り専用のカラムが含まれています。

新しい要件: データをフォーマットする異なる方法

次のお客様のご要望は、データをテーブルの行として表示するのではなく、各項目(通称:行)の情報をカード/ボックスとして表示し、4x5のグリッドで画面に20個のボックスを一度に表示してほしいというものでした。のロジックをそのままにしているので View のロジックをシンプルにしているので、単純に View を顧客が望むように新しいクラスで完全に置き換えるだけです。もちろん、古い View を好む顧客もいるので、両方をサポートする必要があります。なぜなら、共通のビジネスロジックはすべてすでに ViewModel にあるため、あまり問題にはなりません。そこで、View クラスを TableView に変更し、新たに CardView を書くことで、データをカード形式で表示します。また、いくつかのグルーコードを書かなければなりませんが、これはスタートアップ関数内のオネリになるかもしれません。

新しい要件:動的な為替レート

次のお客様の要望は、あらかじめ設定された為替レートを使用するのではなく、インターネットから為替レートを取得してほしいというものです。ここで、先ほどの「レイヤー」の話をもう一度。私たちは Model クラスを変更して、為替レートを提供することはありません。その代わりに、為替レートを提供する完全に独立した追加のクラスを書く(または見つける)のです。その新しいクラスはモデル層の一部となり、私たちの ViewModel は csv-Model と exchange-rate-Model の情報を統合し、それを View . この変更のために、古いモデルクラスとビュークラスは触る必要さえありません。ただし、Model クラスの名前を CsvModel という名前に変更し、新しいクラスは ExchangeRateModel .

もし、ViewModel を導入したときに導入せず、今になって導入していたとしたら、今 ViewModel を導入するための作業量が多くなってしまいます。 ViewModel に機能を移し、その機能を ViewModel .

ユニットテストに関するあとがき

MVVM の主な目的は、Model と ViewModel のコードをユニットテストの下に置くことができることではありません。MVVM の主な目的は、コードが少数の明確に定義された責任を持つクラスに分割されることです。少数の明確に定義された責任を持つクラスで構成されるコードを持つことのいくつかの利点の一つは、Unit Testの下でコードを置くことが容易であることです。より大きな利点は、コードが理解、維持、および変更しやすくなることです。