Introduction

 MVVM パターンとは、アプリケーションの内部構造を Model、View、ViewModel の 3 つに大別して開発をおこなうソフトウェアアーキテクチャの 1 つです。 最大の特徴は、ロジックと UI が分離されることで、プログラマーとデザイナーの分業が比較的容易となることです。

Fig.1 : MVVM パターン概略図

 3 つの役割をおおまかにいうと、Model はアプリケーションの中核となる処理、View はユーザが直接触れる GUI、ViewModel は View に表示する情報の保持および変換をそれぞれ担当します。 これらは理想的には完全に分離できるはずで、実際のコードもこれだけ綺麗に分かれるとアプリケーションの内部構造が非常に明確で、 いわゆるスパゲティコードにならずに済みます。

 MVVM パターンは、ロジックと UI(Model と View)の結合を疎にすることが目的です。 ロジックと UI の結合を疎にすることで、中〜大規模なアプリケーション開発の生産性が向上されることが期待されます。 ロジックと UIの結合が密になると、GUI をデザインするときにロジックの内部構造をすべて把握する必要があり、 GUI のデザインをするのにロジック部分の知識が必要となってしまいます。 小規模なアプリケーションであれば、GUI のデザインと同時にロジックの部分も変更することは容易ですが、 中〜大規模なアプリケーションになってくるとそう簡単にはいきません。 まして複数の人が関わるアプリケーション開発において、そのような作業が困難であることは明白です。

 一方、小規模なアプリケーション開発の場合、内部構造を限定する MVVM パターンは単なる足枷になり得ます。 実際のコードに触れるとわかると思いますが、MVVM パターンを意識し過ぎると、 「これは ViewModel の役割だからこっちにコードを書くのはおかしい」とか、 「これは View の操作だから ViewModel から触るのは NG」とかいったことが発生します。 こういったことも少し複雑な仕組みを作れば確かに MVVM パターンに則った内部構造を実現することはできます。 しかし、これでは開発の生産性を向上させるためのソフトウェアアーキテクチャとしては本末転倒な話です。 「MVVM パターンとして見るとこれは NG かも知れないけど、こっちのほうがコードも見やすいし、メンテナンスも問題ないね。」と判断できればそれでいいのです。 完全に MVVM パターンに当てはまらなければならないなんてことは誰も言っていません。 つまり、MVVM パターンはあくまでもひとつの方針として考え、必ずしも MVVM パターンに縛られる必要はないということです。 もちろん小規模アプリケーション開発でも、MVVM パターンを意識して作り込むことで後々のメンテナンス性に有利に働くかもしれません。 あるアプリケーション開発において、Model、View、ViewModel の役割をきちんと線引きできていれば、 あるいはその他の役割を持った別のものがあったとしてもそれがそのアプリケーションの開発スタイルとなるのではないでしょうか。 MVVM パターンはあくまでもひとつの理想形と考え、そこから自分たちの開発スタイルをどのようにすべきかを考えることで、 自分たちにとってより良いアプリケーション開発のフレームワークが見えてくると思います。

 ここでは MVVM パターンの理想形について説明します。 Model、View、ViewModel 3 つの分類がそれぞれどんな役割を果たすのか次に見ていきます。

Model

 Model はそのアプリケーションの最も中核となるロジックの集まりです。 極端にいうと、そのアプリケーションを CUI として動作させるコードの集まりが Model となります。 したがって、Model は View にも ViewModel にも依存してはいけません。 また、アプリケーションの中核となるため、Model がなければアプリケーションは成り立ちません。というよりは、 アプリケーションが満たすべき要求仕様のほんとんどは Model によって実現しているということです。

 GUI とは関連のない部分を担っているため、データ構造の定義やアプリケーション外部とのやり取りはすべて Model がおこないます。 外部とのやり取りには、ファイルアクセス、ソケット通信、データベースアクセスなどがあります。 また、アプリケーション内部で発生したエラーや例外処理も、そのほとんどすべては Model がおこなうべき処理となります。

View

 View はユーザが直接触れる GUI の部分です。 View はユーザからの指令や、それに付随するイベントを発行し、これを ViewModel に伝える必要があります。 また、ViewModel が公開する情報をグラフィカルに変換してユーザに見せます。 したがって、View は ViewModel に依存して作られなければなりません。 ただし、View は ViewModel の内部構造を完全に把握する必要はありません。これは、 ロジックと UI の疎結合を目指す MVVM パターンの方針と矛盾してしまうからです。 つまり、View が ViewModel のインスタンスを持つ必要はありません。 したがって、XAML 上で ViewModel を使用することはありません。

 ところで、WPF の開発では、GUI のコードはすべて XAML によっておこないます。 C# や VB などのコードからコントロールを配置することもできますが、 それらはすべて XAML で実現できる上に、XAML でしか実現できない機能も存在します。 したがって、コードビハインドを用いてコードを書く必要はありません。 ただし、動的なコントロール配置など、標準的な動作以外のことを実現しようとすると、 XAML だけで実現することが困難な場合があります。 この場合、カスタムコントロールやユーザコントロールを用いることで、 複雑な動作をするコントロールを定義することもできます。

ViewModel

 ViewModel はユーザに見せる情報を Model から参照して、必要であれば変換して View に公開します。 また、View から受け取ったユーザからの指令を翻訳して Model を操作するのも ViewModel の役割です。

 原則的に View と ViewModel は 1 対 1 対応で、複数の View を持つ場合は ViewModel も複数となります。 また、ViewModel は Model の影となる存在です。 ViewModel 同士に所有関係はあり得ますが、連携をしてはいけません。 複数の Model が連携している状況で、さらに ViewModel 同士も連携してしまうと、 それだけ内部構造がややこしくなってしまうからです。

Fig.2 : 複数の View と Model によるデータ連携
このとき、誰が新たな View のインスタンスを生成すればいいか悩みます。 View のコードビハインドで生成した場合、生成された View は、 元の View の所有物となるため、元の View が Close() されると、 生成された View は迷子になってしまいます。 ところが、ViewModel や Model から View のインスタンスを生成してしまうのは MVVM パターンとしてマナー違反となります。 このような場合は、MVVM パターンではなく、MVPVM パターンを用いるという手段もありますが、 下図のように、 Application クラスで View インスタンスの生成および削除の管理をおこなう方法もあります。
Fig.3 : Application クラスによる View-ViewModel インスタンス管理

まとめ

 Model、View、View Model それぞれの特徴を簡単にまとめると次のようになります。

  • Model はアプリケーションの中核
  • CUI として動作させようとして作る部分が Model になり得る。 View にも ViewModel にも依存しない。 アプリケーション外部とのやり取りも Model でおこなう。
  • View は UI を担当
  • ViewModel に依存し、公開されるプロパティを知る必要があるが、ViewModel のインスタンスを知る必要はない。 ユーザ指示を ViewModel に通知する義務があるが、これは WPF の仕組みでおこなわれるため、開発者が意図的にコードを追加する必要はない。
  • ViewModel は View に見せる情報を保持
  • View からの指示にしたがって Model を操作し、結果を View に公開する。また、それらの情報を保持する。 ViewModel のプロパティに変更があった場合は View に通知しなければならない。

Designed by CSS.Design Sample