2011年10月22日土曜日

MVVMを図にしてみた

MVVMに則ったクラスの機能分担
ユーザ入力によるイベント発生時の動作
Modelの処理中にプロパティ変更イベントが発生した場合の動作

最近真面目にプログラム書いてるので久々の更新。

WPFで書くにはMVVMというデザインパターン(?)で書くのが定説らしい。で、色々調べてみましたが、MVVM人気ないんですかね。要る要らないとかの宗教論争が多いです。要るか要らないかは使う側が考えるから、提供側はバシッと情報提供頼むよ(To マイクロソフト)。提供元がフラフラしてるからMVVMの考え方もフラフラしてるみたい。その辺は追々書いてみます(やる気の神が降りてきたら…)。

で、勉強も兼ねてMVVMの役割分担を図にしてみました。合ってるかどうかは不明。合ってなくてもいいんだ。まだ考え方がフラフラしてるんだし。MVVMは基本的に3つのクラスで構成されます。VMを複数のクラスに分けたりVを入れ替えたりするかもしれませんが、考え方的にはM-V-VMの3つ。適当に解釈してこれらの役割を書くと以下のとおり。

  • Model: 目に見えない処理をするクラス
  • View: 目に見える処理するクラス
  • ViewModel: Modelを目に見える形に変換するクラス

語弊がありすぎる気がしますが、細かく書くときりがないのでこの程度に。なおViewは目に見える処理しか行わないので、基本的にはXAMLだけ記述することになります。だけどXAMLだけでは書き切れない処理はコードビハインドと言ってC#で書いてもいいそうです。もっとも、コードビハインドの是非こそがMVVMの最大の争点な気もしますけど。その辺はおいおい(やる気の神がry)

図はModel、ViewModel、Viewが横並びになっていますが、ModelはViewModelやViewを気にする必要はありません。ViewModelもViewを意識する必要はありません。「全く意識しないわけではない」と説明されることもありますが、ありません。あってはならないのです。多分ないです。その説明は追々(やる気のry)。MVVMは各クラスで役割分担を明確にするために用いられるため、不要な参照はしません。ViewModelがViewを全く知らなくても成り立ってしまうなんて。マイクロソフトに、そしてデータバインディングに感謝。

ViewModelはModelのインスタンスを、ViewはViewModelのインスタンスを持ちます。なお、図には書いていませんがViewModelが持つModelのインスタンスは非公開ですのでお間違いなく。ViewがModelを触れるなんてことはありません。また、ViewModelもプロパティとコマンドしか公開しないので、ViewがViewModelを操作することもできません。Viewは飽くまでも表示だけです。

で、MVVMにすると何がいいのかってことですが、言わなきゃわからん奴は使わなくていいよ。データバインドとコマンドバインドのおかげで表示部(View)と演算部(ModelとひょっとしたらViewModel)を完全に分離できてるんだぞ。View取り替えるだけで表示部を変えられるなんてステキじゃないか。

VはMやVMと切り離されている(灰色は壁です)ので、V1をV2に取り替えてもOK(V2も同じVMに対応している前提)

「そんなのデータテンプレートでもできるだろ?」って思ったあなた、Viewを完全に独立させるには↓みたいにイベントハンドラ内でViewを参照してはダメなんですが大丈夫でしょうか。

public void button1_Click(object sender, EventArgs e)
{
  // ボタンが押されたらTextBox1の文字列で検索実行
  string word = TextBox1.Text; // ←TextBox1というViewの名前を使用しているのでMVVM的にはNG
  this.search(word);
}

「イベントハンドラでViewの値取れないとか無理ゲーじゃね?」と思ったあなた、そもそもその発想がMVVM的ではないのですよ。MVVMではModelが演算データの原本で、ViewModelが表示データの原本なんですよ。Viewはそれを表示してるだけなんだから、ViewModel(=コマンド規定側≒イベントハンドラ側)にはコマンド(≒イベント)を処理するためのデータは全てあるのですよ。なきゃおかしいのです。

「じゃあウィンドウの状態とかドラッグアンドドロップされたファイルのパスみたいにView操作契機で生じるデータ知りたいときどうするの?」と思ったあなた、長くなるので続きはまた今度(やる気がry)。端的に言うとTriggerやらActionやらBehaviorやらMessengerやらを使うとなんでもできるらしいです。

で、このTrigger、Action、Behavior、MessengerがMVVMの気に食わないところなんですよね。せっかくの美しいMVVMの概念をややこしくしている気がして。

久々の長文だったから疲れた。

Posted by Picasa

1 件のコメント:

匿名 さんのコメント...

ぶっちゃけ時代遅れなんでMorphic の方がいいッス