Ruby on Railsをはじめとする最近のWebアプリケーション・フレームワークの多くは,MVCと呼ばれるデザイン・パターンを採用しています。今回は,このMVCパターンの「正体」について考えます。
MVCはGUIを備えたプログラムを設計する際の指針となるデザイン・パターン*1の一つです。「モデル」(Model),「ビュー」(View),「コントローラ」(Controller)という3つの構成要素の頭文字から命名されました。多くのデザイン・パターンはプログラムの一部のみの構成を決めています。しかし,MVCはアプリケーション全体の構成を決めることが多いため,「アーキテクチャ・パターン」と呼ばれることもあります。
MVCは,元々プログラミング言語Smalltalkにおいて,ウインドウ(GUI)を持つアプリケーションを構築する際の指針として誕生しました。 MVCを発明したのは,当時,米Xerox社のPalo Alto Research Center(PARC)に所属していたノルウエーのTrygve Mikkjel Heyerdahl Reenskaug氏だそうです*2。Simulaの開発者であるKristen Nygaard氏(ノルウェー)といい,C++の開発者Bjarn Stroustrup氏(デンマーク)といい,オブジェクト指向の歴史には北欧人が大きな役割を果たしているようですね*3。
モデル,ビュー,コントローラの役割
MVCで扱う「モデル」とは,ウインドウによって表示される内容(情報)を表現するオブジェクトです。モデルが表現するのはあくまでも情報(名前や数値などの抽象的な情報)であって,どのように表示すべきかというような情報を持っていてはいけません。
「ビュー」は,モデルの持つ情報をウインドウに表示するオブジェクトです。ビューは表示すべきモデルを「知って」いますが,一般的にモデルは自分を表示しているビューについての知識は持っていません。
「コントローラ」は,ユーザーからの入力を受け,ビューやモデルを操作するオブジェクトです。
以上の関係を図で表すと図1のようになります。マウスやキーボードを介してユーザーから与えられた入力はコントローラに渡されます。コントローラはモデルとビューを参照でき,必要に応じてこれらのメソッドを呼び出してアプリケーション全体を制御します。
図1●モデル,ビュー,コントローラの役割分担と相互関係 |
ビューはモデルを参照でき,モデルの状態をウインドウに表示します。モデルの状態を知る方法はいくつかあります。Smalltalkでは一般に, Objectクラスに組み込まれているObserverパターン*4を実現する機能を利用するようです。一定期間ごと,表示イベントが発生したタイミングでモデルに問い合わせる「ポーリング」という手法もあります。
ビューがコントローラを参照できるかどうかはアプリケーションによって異なります。図1では参照できる場合を示しました。単純なウインドウ・アプリケーションでは,多くの場合,ビューがコントローラを知る必要はありません。しかし,アプリケーションが複雑化すると,ビューとコントローラの相互作用が頻繁になり,ついには一体化してしまうことも珍しくありません(後述)。
一方,モデルがビューやコントローラを参照できるようには設計すべきではありません。図1でもモデルから出る矢印が存在しない点に注目してください。これは,モデルがビューと一対一対応しない可能性があるからです。言い換えれば,同じモデルに複数のビューが伴うことが考えられます。
例えば時計のアプリケーションを考えてみましょう。モデルに相当するのは時刻を刻む機構でしょう。ビューは実際に時刻を表示する部分ですが,これはアナログ時計かもしれませんし,デジタル時計かもしれません。このような場合,ビューに相当するオブジェクトを取り替えることで,表示の切り替えを実現したいものです。このためには,モデルが直接ビューを参照できると具合が悪いのです。
アプリケーション・ロジックを表現するモデルと,インタフェースを提供するビューやコントローラを分離しておくメリットはほかにもあります。将来インタフェースを取り替えたり,大きな変更を加えてもロジック部分に対する影響が少ないことです。アプリケーション・ロジックよりもインタフェースを変更する場合が圧倒的に多いでしょうから,分離するという方針は合理的です。