ログイン
編集不可のページディスカッション情報添付ファイル
alstamber/AndroidDevelopment/DevelopmentModel

MMA

なにこれ

元祖MVC

元祖のMVCモデルはSmalltalkの世界から生まれたらしい。
元祖の定義によると

というのがMVCモデルだそうだ。ユーザーに見えているのはViewである。元祖MVCモデルのソフトウェアは次のように動作する。

  1. Viewにユーザから入力がある
  2. ViewはControllerにユーザーからの入力を通知する
  3. ControllerはViewから受け取ったユーザーからの入力を元に適宜Modelの必要な処理を呼び出す
  4. ModelはControllerから呼び出された処理を順次実行する
  5. Modelが処理をした結果Modelが持っているデータが変わることも有る
  6. ModelはViewに表示するべき情報が変化したときそれをViewに通知する
  7. Viewは通知を受けてModelから情報を受け取り、自分自身を書き換える
  8. Controllerはユーザーからの入力に応じて直接Viewにたいして書き換えを指示することもある

6〜7は一般にObservableデザインパターンによって実現されるものである。

元祖MVCが目指そうとしていること

一つは外観と内部実装の切り離し。データとデータに対する処理と入力を受け付ける処理と状態変化を外観に反映する処理がごちゃまぜになっているのは良くない。
Modelは再利用したい。Viewは自由に差し替えられるようにしたい。

内部処理を切り離すことによってその部分は外観に依存しなくなるのでテストをやるのが楽になる。

元祖MVCについて留意するべき点

MVC2

WebはステートレスなのでObservableパターンを使ってModelの変更をViewに通知することができない。そこで生まれたのがこの設計手法。
(Ajax的なことすればできるのかもしれないけど、そのあたりは勉強不足でよく知らない)
Strutsを例にMVC2について考えてみる。

  1. ユーザからの入力をJavaServletが受け取る

  2. Servletはユーザからの入力を解析し適宜必要なアプリケーションロジックを呼び出す
  3. Servletからの要求はアプリケーションクラスが引受け、適宜必要なデータをJavaBeansから取ってきてJavaBeansに実装されている処理をする

  4. 処理が終わった所でServletは対応するJSPを呼び出す
  5. JSPは呼び出されるとアプリケーションクラスから必要なデータをとってきて整形し表示する

ServletがController、JavaBeansがModel、JSPがViewに相当する。Modelの変更をViewに通知する手段がないため、それをControllerにやらせているのが元祖MVCとの違いである。
亜種的実装として、ControllerがModelからデータをとってきてViewに渡す、という方式もある。

MVC2において気をつけるべきこと

Model=データ置き場という認識になってしまい、Modelに本来実装するべきデータに付随する固有の処理までControllerに書いてしまうとControllerが異様に肥大化してしまう。
貧弱なModelのことを貧血ドメインモデルなどというようだ。
Controllerはできるだけ薄いほうがよい。仕事をModelに振り分け、その結果を元にViewを組み合わせるのがControllerの仕事である。

とまで書いて、太ったControllerというのはトランザクションスクリプト的なのではないかと思った。あるデータが有って、そいつに対してどういう処理をするのかをつらつらと書いていく感じ。
一方で痩せているControllerというのはドメインモデル的だなと。データとそれに対する処理がカプセル化されていてオブジェクト指向的っちゃオブジェクト指向的。

太ったModelも結局保守性が下がることに変わりはない。そのため例えば特定の用途でしか使われずに再利用の必要性が少なそうな処理についてはControllerに書いてしまってもいいかもしれない。
あるいは永続化の必要がないModelは別の扱いにしてControllerと永続化されているModelの間においてしまうのも手か。

MVCが抱える問題

MVCではプレゼンテーションロジックを書く場所がない。すなわちModelの変化に合わせてViewの見た目そのものを変更したいとき、その見た目の情報をどこに持てばよいのか、という問題が起きる。Modelは本来見た目には関与するべきではないし、ViewがそれをやるにしてもViewが見た目に関する情報を保持しなければいけなくなってしまう。これはとくにWebアプリケーションで致命的である。WebアプリケーションにおけるViewは短命であり基本的に使い捨てである。なので見た目に関する情報を保持させるにはちょっと不向きである。

またここ最近はクライアントのリッチ化が進んでいるが、クライアントがリッチになればなるほどViewとControllerは密接になっていく傾向があるように思える。(高機能なUIコンポーネントが増えてくる)
リッチクライアントの世界ではViewとControllerを分ける意味があるのか、という疑問が出てくる。

MVP

MVCの亜種であり、MVCが抱える問題を解決するための手法。


MVPの設計方針としては大きく2つあって

が挙げられる。
View はできるかぎり素朴であるべきで、プレゼンテーションロジックはPresenterに含まれるべきであるというのがパッシブView。
またプレゼンテーションロジックとして書かれるべきなのはViewの中の宣言的なロジックでは要件を満たせないときに限るべきというのが監視Controllerである。
具体的な実装の話をすれば、ViewがModelを監視するものを監視コントローラ、しないものをパッシブビュー呼んで良い。

PresenterからViewを更新するときはViewの実装にPresenterが依存しないようにするためにインタフェースなどを挟むようにする。

PM

ViewとModelの間にPresentation Modelを置いて、そこに見た目に関する情報をもたせる手法。MVPと同じくMVCの問題を解決する手法。
MVPはMVCの抱える問題を直接Viewを書き換えるものを作ることで解決したが、PMではPresentation Modelを間に挟ませるようにする。
MVCではViewはModelを監視してたんだから、その流儀に則るべきだろう、というところだろう。
ViewはModelの代わりにPresentation Modelを監視する。Presentation ModelはModelからアプリケーション固有のデータを引っ張ってくる。
また自分自身でViewの見た目を定義する情報を保持していて適宜Viewに渡す。

  1. ユーザからの入力をControllerが受け取る
  2. Controllerはユーザからの入力を解析しModelから適宜必要なロジックを呼び出す
  3. Modelは処理を行い、必要に応じて自分自身の状態を書き換える
  4. ModelはPresentation Modelに変更を通知する
  5. Presentation ModelはViewに変更を通知する
  6. ViewはPresentation Modelから出力に必要な情報をとってこようとする
  7. Presentation ModelはViewからの要求に応じてModelから必要なデータをとってくる

ModelからPresentations Model、それからPresentation ModelからViewへの参照を張ることはできないので、例えばインターフェースなどを使って間接的に参照するような設計が必要だろう。

PMの課題点

ViewとPresentation Modelは緊密に連携するため委譲のためのコードをいっぱい書かなければいけないかもしれない。

MVVM

PMモデルに似ている。WPFなどで推奨されているため、その界隈では常套手段になっているようだ。

Viewにはなるべくコードを書くべきではなく、見た目はXAMLなどで定義するべきである。
Viewを薄くしてView Modelをレンダリングするための装置ぐらいに考えるのが良い。
PMモデルに似ているため、やはりViewとView Modelの緊密な連携が重要である。ただしView ModelはViewを参照してはならない。ViewはView Modelを参照しても良い。
WPFでの実装ではViewからView Modelへの参照はリフレクションを使う。逆はイベント呼び出しをするようだ。ただこれらはデータバインドという仕組みによって遮蔽されているのでそれを意識しなくてもいいようになっている。
ViewModelはViewを意識しますが、その実装について何も知らなくてもよいし、知るべきではない。
View Modelは何かというと表示に関するロジックや状態を、Viewに依存しない形で実装。また、View ModelはModelへの操作をコマンドという形で提供。
このおかげでViewとView Modelはお互いにどのような構造になっているのか知らなくてもお互いを叩くことができるっぽいですね。

PMとMVPの違いを端的に考える

この2つの違いは端的に言ってしまえば、PMはViewとPresentation Modelの間の強力なバインドを前提としているということだろう。バインド機構がなくてもできなくはないが、コードが無駄に増えて利点が失われる。バインドという形で相互の通信が遮蔽されることによって、開発者のコーディングによって結合度が上がってしまうという状況を避けられる、という設計のようだ。

サーバサイド

サーバサイドに関してはStrutsやRailsのようにMVC2が採用されていることが当たり前になっている。というのもMVC2ではViewとModelが全く関係のない存在になっている。トラディショナルなMVCではViewとModelは綿密に連携するが、サーバサイドなシステムで最終的に吐かれるViewは使い捨てで、静的である。つまりViewとModelの連携を実現できない。

クライアントサイド

ここ最近はクライアントサイドのJavaScriptフレームワークもじゃんじゃか出てきてるみたいだが、これらはMVCで書かれてたり、PMで書かれてたりするようである。MVC2は逆に採用しにくい。というのもMVC2ではModelからリアルタイムにイベントを発火させることができない。リアルタイムに変化することを求められるクライアントサイドアプリケーションには向いていないように思われる。

Android

基本的にクライアントサイドと同じように考えればよいのではないかと思う。特にTwitterクライアントのユーザーストリームはいい例だ。Twitterから送られてくるTweetによってModelでイベントが発火しそれによってViewが更新される、というパターンを実現するにはMVCかMVPかMVVMを使うのが妥当だろう。ただMVVMはAndroidに標準で強力なデータバインド機構が存在しないこともあり導入は難しいかなという気がする。
(Contextとかいうヤツのせいで余計にその辺りが難しくなっている……)
ただ、見た目とそれ以外に分けるだけでもUIへのバインドとリスナー登録とネットワーク通信とロジックがごっちゃになった気色悪いActivityを生産しなくて済むのでだいぶメンテしやすくなるし、テストも書きやすくなると思う。
UIへのバインドとかセッタ・ゲッタの羅列はデータバインドが出来れば一気に消し去れそうな気もする。
(ちょっと調べてみたところUIへのバインドに関しては「依存性の注入」という技術を応用すれば消し去れそうである。試してみたい。)

alstamber/AndroidDevelopment/DevelopmentModel (最終更新日時 2013-03-31 06:19:12 更新者 alstamber)