- ユーザーインターフェースを持つアプリケーションを Model/View/Controller の 3 つにの部分に分離する
- モデル・ビュー・コントローラの責務と関係
- 特にコントローラの責務
- コントローラとビューの関係性
- 各プラットフォームにおいて、上記の責務をどう実装に落とし込むのか
- ほんとうにビューとコントローラは分離できるのか?
- そもそもビューとコントローラを分離する利点は?
Model-View-Controller に分離するパターンを見ていくが、クラスに分割するだけが分離に相当するわけではない
- サブルーチン・メソッド
- クラス
- パッケージ
- モジュール
MSDNの記事がわかりやすかったのでまとめた
- コンピュータシステムの多くは データ を取ってきて、 ユーザ に表示する
- ユーザがデータを変更したら、 データストア の内容を更新することもある
そのため、データストアと UI 間のデータの流れに目がいきがちであり、パフォーマンスのため、またはコード量を減らすために、しばしばその処理を密結合にしてしまうことがある。
- UI はデータストアと比較して頻繁に変更が入る傾向にある
- 複雑なアプリケーションでは、単にデータストアからデータを送受信するだけでなく、複雑なビジネスロジックが存在する傾向にある
ドメインロジックと UI の変更をそれぞれ手軽に独立して行えるようにするためには、Web アプリケーションをどのようにモジュール化すれば良いのだろうか
問題を解決する際に、次のようなことを考慮する必要がある
- UI ロジックはビジネスロジックに比べて頻繁に変更が入る傾向に有る
- 特に Web アプリケーションにおいては顕著
- 例えば、新しい画面が追加されたり、すでに存在するページのレイアウトが変更されたりすることが多い
- したがって、サーバー側に処理をまとめたシステム(シンクライアントシステム)は、アプリケーションを再配布しなくて済む
- プレゼンテーションコードとビジネスロジックがひとつのオブジェクトとして結合している場合、UI だけを変更したくてもビジネスロジックを含んだオブジェクトを変更しなければならない
- これは UI の些細な変更であっても、エラーを誘発したり、再テストが必要だったりすることを意味する。
- 場合によっては、アプリケーションは同じデータを異なる形で表示することがある
- 例えば、アナリストはスプレットシートを好み、マネージャは円グラフを望むことがある
- またそれらを同時に表示することも十分に考えられる
- もしユーザがデータに変更を加えた場合、すべてのビューに反映されるべき
- デザインと複雑なビジネスロジックを作る作業は全く異なるスキルであり、両方のスキルを持ち合わせる人は滅多にいない
- そこで、これらの作業はバラバラに実行できることが望ましい。
- プレゼンテーションはデータソースからデータを取得し、データをフォーマットして表示する
- 表示されたデータに応じてユーザーはなんらかのアクションを行い、そこからうまれた変更を反映させるためにビジネスロジックへ制御が渡る
- Web アプリケーションは HTTP のステートレス性の上で、異なるアクションを実現しなければならない
- UI 層のコードは、ビジネスロジックと比較して、デバイスに依存する傾向にある
- したがって、もしプラウザベースのアプリケーションからモバイル端末などに移植したい場合は UI 層のコードを置き換える必要がでてくる
- UI に関するコードとビジネスロジックを分離しておくことは、移植を素早く行えるようにしたり、移植後のビジネスロジック層のエラーを減らしたりすることに役立つ
- UI 層のテストは難しくて、実行に時間がかかる傾向にある。したがって UI 層と直接結びついているコードを減らすことはテスタビリティ向上につながる。
Model-View-Controller パターンは、ドメインモデル、プレゼンテーション、ユーザーからの入力に対するアクションの3つのパートに分離をする[Burbeck92]。
- Model: モデルは状態に応じたアプリケーションドメインの振る舞いを扱い、主に Controller からの操作に応じて状態を変化させる。
- View: ビューは表示される情報を扱う
- Controller: マウスやキーボードなどのユーザからの操作を解釈して、モデルやビューに適切に伝える
- ビューとコントローラーはモデルに依存してよい
- モデルはどちらにも依存してはいけない
- これにより、モデル層とプレゼンテーション層のビルドやテストをバラバラに行うことができるようになる
- ビューとコントローラーの分離はリッチクライアントアプリケーションでは二の次となる
- 実際のところ多くの UI フレームワークではひとつのオブジェクトにビューとコントローラーの責務をおいているものが多い
- 一方、Web アプリケーションにおいてはビュー(ブラウザ)とコントローラー(HTTP リクエストをさばくサーバーサイドコンポーネント)は明確に分かれている。
Model-View-Controller は UI ロジックとビジネスロジックを分離するための基本的なデザインパターンである。有名であるがゆえに、多くの間違った説明がなされている。
特に Controller は色々な文脈で異なる説明がなされている。ただし、Web アプリケーションにおいてはビューとコントローラーは明確に分かれているために、こういった曖昧さを解消するためには丁度良い。
Steve Burbeck は、In Application Programming in Smalltalk-80: How to use Model-View-Controller の中で passive 型と active 型の 2 種類の MVC のかたちについて説明している。
passive 型 MVC はあるコントローラがモデルを排他的に制御するときに用いることができる。コントローラはモデルを変更し、ビューにモデルが変更されたので内容を更新する必要があることを伝える。このやり方だと、モデルはビューやコントローラと完全に独立した形になり、モデルはビューに変更を伝える手段がない状態になる。HTTP プロトコルなどがこのパターンに合致する。ブラウザがサーバーから更新を受け取るための、この上なくシンプルな方法である。ブラウザはユーザからの入力に応じてビューを表示するが、サーバー上のデータの変化を検出することはできない。ユーザが明示的に更新を問い合わせる必要が有る。
active 型はコントローラが関わらなくてもモデルの状態が変化する際に用いられる。このモデルの変化は他の入力ソースからデータの変更が発生してしまう場合に起こりうる。基本的にはその変更はビューに反映されるべきである。電光掲示板を作るときにはこうしなければならないだろう。表示内容に変更があった場合、データ取ってきてビューに反映させる必要がありそうである。
しかし、MVC パターンを用いる大きな目的のひとつに、モデルとビューを分離するというものがあったことを思い出そう。モデルがビューに変更を通知するとなると、ふつうにやれば依存関係が発生してしまう。そこで GoF の Observer パターンを思い出そう。これはオブジェクト同士の依存を避けつつも、変更を通知することを実現するデザインパターンである。それぞれのビューは Observar インターフェースを実装して、モデルを購読する。モデルが変更されたら、登録されているすべての observer に通知を行うという仕組みになる。このやり方はしばしば、publish-subscribe と呼ばれる。モデルはビューに関する情報は一切必要としない。たとえば、メニューのオプションを使えなくする必要があるなど、コントローラーがモデルの変更通知を必要とする場合、すべてのコントローラは observer インターフェースを実装する必要がある。また、たくさんのビューがある場合、それぞれ異なる領域ごとにモデルを定義し、各ビューは関心のあるモデルのみを subscribe すると良いでしょう。
- 複数のビューをサポートできる: モデルとビューが分離されているため、モデルからビューへ直接の参照は存在しない。したがって、同時に同じデータを様々なビューで表示することができる。これは Web アプリケーションにおける複数のページは同じモデルオブジェクトを使っていることがあることからもわかるだろう。またユーザがページの見た目を変更できるような Web アプリケーションの存在からも理解することができるだろ。そういったページは同じモデルから得られた同じデータを、異なる方法で表示することができている。
- 変更に強くなる: UI はビジネスロジックと比較して変更が生じやすい。ユーザは異なる配色やフォントやレイアウトを好むかもしれないし、デバイスに特化したインターフェースを望むかもしれない。モデルがビューに依存していないので、新しいビューのセットをシステムに追加しても、モデルは何の影響も受けない。結果として、変更の影響はビューだけに限られる。この部分をさらに細分化したパターンとして Page Controller と Front Controller というパターンがある。
- 複雑になる: MVC パターンは遠回りなやり方であり、システムを複雑にする。またデバッグの難しいイベント駆動なコードベースになる傾向にある。
- 頻繁な更新に対するコストが大きい: モデルとビューを切り離すことは重要だが、決してモデルがビューの存在を無視してよいということではない。モデルが頻繁に更新を行うような場合、ビューにそれを反映させるコストは大きなものとなるだろう。特にグラフィカルなユーザーインターフェースにおいては顕著になる。このような 10 教科ではビューは描画に失敗することもあるだろう。したがってモデルを作成するときにはビューを念頭に置くことは重要だ。場合によってはモデルの複数の変更をまとめてビューに通知するなどということも必要なはずである。
Model-View-Controller の責務分離は行ったまま、View と Controller を結合 したものを Document-View パターンとよんでいる。今日の、多くの GUI プラットフォームではこのパターンが用いられている。VC++の MFC などはこのパターンの実例のひとつになる。