プログラマーであるならば誰しも「保守性の高いプログラムを書きたい」

そう願っているでしょう(え?思ってないって?)

そんな細やかで傲慢な願いを叶える手法の一つ、MVVMについてサンプルコードを交えながら紹介したいと思います。

かりまたかりまた

MVVM(モデル – ビュー – ビューモデル)というワードを聞いた事があるでしょうか。今回はMVVMについて纏めてみたいと思います。

ところでMVVMって何さ

りんちゃんりんちゃん

MVVMの詳しい説明は以下のサイトを読むのにゃ~。

 

かりまたかりまた

ふむふむ。なるほど…。って全然わからんわ!!ざっくりざっくりに言うと、プログラムを

  • モデル(M odel)
  • ビュー(V iew)
  • ビューモデル(V iew M odel)

の3階層に分けるアーキテクチャの事です。

MVVMの何が嬉しいの

りんちゃんりんちゃん

MVVMを使うと何が良いのかにゃ~。

殺せんせー殺せんせー

ぬるふふふ。お答えいたしましょう。

 それぞれの階層の役割が明確になり、UIとロジックの分離が出来る 

このことに尽きると思います。

ナルトナルト

どういうことだってばよ

殺せんせー殺せんせー

まず、 「それぞれの階層の役割が明確になる」 という点です。これはレイアウトを記述するならこのファイル、ロジックを記述するのであるならばこのファイルと、手を加えるべき箇所が明確になるという事です。

殺せんせー殺せんせー

また、 「UIとロジックの分離が出来る」 という点ですがこれは先ほども言った通り、役割が明確化されることで記述する箇所も定まってきます。もう少し具体的に言うと、UIXamlに書き、ロジックはModelに、その橋渡しをするのがViewModelとなるわけです。

かりまたかりまた

UIとロジックを分離することで自動テストが行えたりするんですが、それは追々話をしていきたいと思います。

実際にMVVMを使ってみよう

りんちゃんりんちゃん

まぁなんとにゃく掴めてきたのにゃ~。早速やってみるのにゃ~。

かりまたかりまた

りんちゃん、ちょっと気が早いよ!まずは初学者が書くやり方で書いた後に、MVVMを適用させてみたいと思います。

かりまたかりまた

ここでは例として、ボタンをクリックすると1ずつカウントアップするプログラムを作ってみたいともいます。

パターン① コントロールにイベントを割り付ける

りんちゃんりんちゃん

MainPage.xamlMainPage.xaml.csに以下の様に記述するのにゃ~。

コード

動作

AndroidiPhone

パターン①の書き方について

かりまたかりまた

プログラミングを覚えたて?であればこのように、コントロールにイベントを割り当ててこの動作を実現させると思います。しかし、クリックイベントを使った瞬間にMVVMではなくなるわけです。

かりまたかりまた

どういうことか?というと、レイアウト部分に関する事はView、つまりはXamlで完結させたい訳です。クリックイベントの紐づき先はXamlのコードビハインドであり、レイアウトとそのコードビハインドの依存関係が生まれてしまいます。このように、UIとロジックが密結合の状態であると自動テストも憚られてしまいます。

パターン② MVVMを使ってみる

りんちゃんりんちゃん

今度はMVVMを使用してみるのにゃ~。

フォルダの構成

かりまたかりまた

MVVMを使うにあたって色々とファイルを増やしています。全体像が見えないと辛いと思うので先に示します。

りんちゃんりんちゃん

増えたファイルは以下の通りだにゃ~。

  • ViewModelBase.cs
  • MainViewModel.cs
  • CountUpCommand.CS
  • Count.CS

コード

MainPage.xaml
りんちゃんりんちゃん

レイアウトはさっきと変わらないにゃ~。ただ、さっきとは違ってイベントを消して、Commandプロパティを使ってるのにゃ~。

ViewModelBasePage.cs
りんちゃんりんちゃん

INotifyPropertyChangedインターフェースを使用してViewModelのベースページを作成するのにゃ~。値の変更を受け取るにはこのインターフェースが必須なのにゃ~。

MainViewModel.cs
りんちゃんりんちゃん

次に、ViewModelなのにゃ~。上で作ったViewModelBaseを継承するのにゃ~。

CountUpCommand.cs
りんちゃんりんちゃん

XamlCommandプロパティを使ってるのにゃ~。実行コマンドを以下のように記述するのにゃ~。

Count.cs
りんちゃんりんちゃん

最後に、Modelを作成するのにゃ~。ここではパラメータで渡された値に1を足すという何とも地味なロジックを記述してるだけなのにゃ~。

動作

AndroidiPhone

パターン②の書き方について

かりまたかりまた

さて、MVVMで書き直してみたのですがいかがでしょうか。パターン②のように書くことで、UIとロジックが完全に分離されました。その証拠に、MainPage.xaml.csにはInitializeComponentsしか記述されていない状態です。

どうしてMVVMに当てはめるとUIとロジックが分離できるの?

かりまたかりまた

今回は敢えて、プレーンなMVVMを記述してみました。実際に書いてみて分かったことがあります。MVVMの本質として、 イベント発火時のイベントハンドラをコードビハインド以外の箇所に書ける という事です。

かりまたかりまた

パターン①で書いたように、イベントを使用してしまうとイベントハンドラは必ずコードビハインドに書かなければなりません。その段階でUIとロジックが分離できなくなってしまいます。そこで、Commandプロパティを使用することで、イベント発火時の処理をコードビハインドではない箇所、つまりはViewModelへ持っていくことで分離出来ているわけですね。

MVVMについての補足説明

りんちゃんりんちゃん

コードだけだらだら貼り付けて中身について余り触れてなかったから補足説明するのにゃ~。

補足説明① Commandプロパティについて

りんちゃんりんちゃん

CommandプロパティではICommand型のプロパティ名を指定してやる必要があるのにゃ~。今回の例で言うと、CountUpCommandをバインディングしてるのにゃ~。これはボタンクリック時にMainViewModel.csCountUpCommandを実行するように命令してるのにゃ~。

補足説明② ICommandインターフェースについて

りんちゃんりんちゃん

補足説明①でも言っている通り、CommandプロパティにはICommand型のプロパティを指定してやる必要があるのにゃ~。このICommandインターフェスは以下の要素を持っているのにゃ~。

要素名説明
CanExecuteメソッド現在の状態でコマンドが実行可能かどうかを決定する
Executeメソッドコマンドが起動される際に呼び出すメソッド
CanExecuteChangedイベントコマンドを実行するかどうかに影響するような変更があった場合に発火

りんちゃんりんちゃん

MVVMの初学者はここが最も躓きやすいポイントなのにゃ~。ボタンクリック時にはこれらが実行されていることを覚えておくといいのにゃ~。

補足説明③ INotifyPropertyChangedインターフェースについて

りんちゃんりんちゃん

ViewModelBase.csではINotifyPropertyChangedインターフェースを使用しているのにゃ~。MVVMを構築するにあたって、「バインドしている値が変更されたよ!」という通知をしてやる必要があるのにゃ~。その機能を果たす為にはこのインターフェースが欠かせないのにゃ~。

補足説明④ BindingContextプロパティについて

りんちゃんりんちゃん

バインディングするコマンドプロパティの値はどのクラスのプロパティなの?それを教えてあげる際に使用するのがBindingContextプロパティなのにゃ~。MainPage.xamlMainViewModelと指定しているからMainViewModelのプロパティをバインドしているのにゃ~。ちなみに、WPFではDataContextプロパティでバインドに使用するクラスを指定するのにゃ~。

まとめ

  • MVVMパターンを使う事でUIとロジックの分離が出来る
  • UIとロジックの分離をすることで自動テストが可能になる
  • 理想的な形として、MVVMではコードビハインドにコードは書かない
  • Commandが実行されるタイミングでExecuteメソッドが走っている
  • バインドに使用するクラスはBindingContextプロパティで指定する

次の記事