PotelによるMVPを提唱した原典の要約です。最近MVPモデルのフレームワークでプログラミングをしているのですが、ビューとプレゼンターの境界が曖昧になって、どちらにコードを置くべきか迷う場面が出てきたので、根本的な理解を求めて読んでみました。結論から言うと、求めていた答は得られませんでした。たぶん、 ファウラーによるまとめ や、.NET以降のマイクロソフトによる MVPの再定義 を学んだほうが良いのだと思います。
MVPによる分割によって、再利用性、移植性、分散性といったさまざまな帰結が得られるという主張なのですが、こんな上辺の線引きだけから、具体的な様々な果実が直接出てくるわけがないだろう、目を覚ませというのが率直な感想で、いかにもアーキテクチャ屋の考えた絵空事という印象を受けました。まあ、わたしが、小さなコード、小さなプログラムの信奉者で、大規模プログラムとは縁がない人間だからなのかもしれません。実際には、製品化されていてコードを伴うものなので、ちゃんと動くものを見れば、きっとすばらしいものなのでしょう。
MVP: Model-View-Presenter The Taligent Programming Model for C++ and Java
Mike Potel VP & CTO Taligent, Inc.(1996)
http://www.wildcrest.com/Potel/Portfolio/mvp.pdf 1
- Taligentは、次世代のC++とJava用プログラミングモデルとして、Model-View-Presenterを開発した。
- MVPは、古典的なMVCの一般化である。
- MVPは、クライアント・サーバーアプリケーションから、複数の層にまたがったアプリケーションアーキテクチャにまで広範囲に使える。
Smalltalkのプログラミングモデル
- Smalltalkでは、チェックボックスやテキストフィールドのようなGUIオブジェクトを3つの抽象化(MVC)で表す。
- モデルは、チェックボックスのON/OFFや、テキスト文字列のような裏側にあるデータを表す。
- ビューは、モデルを通じてデータにアクセスし、どのように描画されるかを定義する。
- コントローラーは、ユーザーが、ビューを操作する方法や、イベントがモデルを変更する方法を決定する。
- モデルは、状態が変化したら、再描画が必要なことをビューに通知する。 2
- この分割は、最小のGUIオブジェクトにまで適用される。ダイアログボックスのような複合的なGUIオブジェクトは、複数のGUIオブジェクトを積み上げて構築される。すると、全体がMVCで構築されるようになる。
Taligent / Open Classのプログラミングモデルを構築する
- Taligentのアプローチは、MVCのコンセプトを分解して、より複雑なアプリケーションの開発を補助するために改善した。
- はじめに、モデルとビュー・コントローラーの2つに分割した。後者をプレゼンテーションと呼ぶ。
- これにより問題をデータ管理とユーザーインターフェイスに分解する。
- プログラマーは2つの質問にフォーカスすることになる。「データをどのように管理するか」「ユーザーはどのようにデータとやりとりするか」
- 前者には次のような関心が含まれる。データ構造、アクセスメソッド、変更のプロトコル、永続性、共有性、分散性。
- 後者には次のような関心が含まれる。オブジェクトの描画、マウス・キーボードのイベント、どのような意味論的な操作(?)が可能か、どのようなユーザーアクションが認識されるか、どのようなジェスチャー言語が使われるか、どのようなフィードバックがあるか。
モデルはカプセル化を可能にする
- モデル概念を一般化することのメリット。
- モデルとプレゼンテーションを綺麗に分割できるようになる。
- こうすると、背後のデータ構造をリスト構造やハッシュテーブルに変更したり、フィールドを追加したとしても、プレゼンテーションコードを一切いじらずに再利用できる。
- モデルを再実装せずとも、いろいろなプレゼンテーションを実装できる。
- 複数人で同時に作業して、あとで統合することができる。
- これらは自明なようだが、実際そうなっていないコードが多く、背後のデータモデルを変更したら、その影響が様々な箇所に波及してしまうようなプログラムはたくさんある。
- 小規模なプログラムであれば、そのようなやりかたも通用するが、それでは大規模にスケールアップできない。
モデルは永続化を可能にする
- データをどこにどのように格納するかは完全にモデル次第なので、メモリ内にしてもいいし、なんらかの永続化ストアへの単なるプロキシかもしれないし、RDBにクエリを投げるコードを含んでるかもしれない。パフォーマンスのためにローカルキャッシュを持ってるかもしれないし、課金メカニズムを内包してるかもしれないし、複数のRDBに対応していて切り替えられるかもしれない。
- これらはプレゼンテーションからは透過であり、変更することができる。
モデルは共有を可能にする
- モデルの抽象化は、複数ユーザーがいるときの柔軟な使い方も可能にする。
- リモートデータをカプセル化した複数のプログラムがあるときに、常にデータを同期しておける。
- 編集可能な管理者、読むだけのユーザーなど権限ごとにプレゼンテーションを変えられる。
データ管理の3つの質問
- データ管理に関する質問「データをどのように管理するか」はさらに3つに分解できる。
- 1.どのようなデータか 2.どのようにデータを指定するか 3.どのようにデータを変更するか
- データのサブセットを指定する方法を「セレクション」と呼ぶ。
- セレクション上のデータを変更する方法を「コマンド」と呼ぶ。
- 1.モデル 2.セレクション 3.コマンド という関係。
モデル、ビュー、セレクション、コマンド
- 前節の抽象化の実例。
- モデル: 整数の2次元配列
- ビュー: 積み上げ棒グラフ(同じモデルで異なるビューも有り得る、非グラフィカルなビューも有り得る)
- セレクション: どのカラムを選択するか
- コマンド: カラムにどのような変更を加えるか(色の変更など)
- 別の例として、モデルがテキストなら、マウスで選択した部分がセレクション、それを削除・移動・コピーしたりするのがコマンド、など。
ユーザーインターフェイスの3つの質問
- ユーザーインターフェイスに関する質問「ユーザーはどのようにデータとやりとりするか」はさらに3つに分解できる。
- 4.どのようにデータを表示するか 5.どのようにイベントとデータ変更を対応付けるか 6.どのようにこれらを結合するか
- マウスの移動やキーボード入力などのユーザーアクションをインタラクターイベントと呼ぶ。それらとモデルの関係を定義するのが「インタラクター」
- 「プレゼンター」は、Smalltalkで言うところのコントローラーに相当するが、アプリケーションレベルにまで引き上げられ3、セレクション、コマンド、インタラクターを考慮に入れる点が違う。
- 4.ビュー 5.インタラクター 6.プレゼンター という関係。
- プレゼンターは、ユーザーイベントやジェスチャを解釈して、適切なコマンドに対応付けるビジネスロジックを提供する。
インタラクターとプレゼンター
- 積み上げ棒グラフの例の続き。
- インタラクター: マウス操作、選択の指定、メニュー押下、キーボードなどを担当する。
- プレゼンター: その他。モデル・セレクション・コマンド・ビュー・インタラクターを生成し、それらを統合するビジネスロジックを提供する。
MVP: モデル・ビュー・プレゼンター
- これまでのまとめ。開発者は、6つの質問に答えることでMVPモデルのプログラムを作成できる。
Taligentプログラミングモデルのフレームワーク
- Taligentの提供してるフレームワークは、MVPモデルを完全にサポートしているよ!!
Taligentプログラミングモデルのクラス
- 具体的なクラス図を元にしたMVPの説明。
- Taligentの環境では、モデル・セレクション・コマンド・ビュー・インタラクター・プレゼンターに相当する基底クラスが用意されており、それらを継承してアプリケーションを作成する。
- アプリケーションは、基本的に、独自のインタラクターを作成する必要はない。それどころか、コードでオブジェクトを作成する必要すらなく、GUI構築ツールで指定すれば適切なオブジェクトが生成されるようになってる。4
アプリケーションの作成
- MVPの力は、それが直感的な抽象化であることに加えて、リッチなデフォルト実装を提供していることにある。
- MVPは、必ずしも一気にすべて導入する必要はなく、アプリケーションの成長とともに段階的に付け加えていくことができる。
- 電卓アプリケーションを題材にした説明。
- プレゼンターなしに、メインイベントループレベルから手書きで書くことも可能。
- プレゼンターを継承すれば、アプリの起動から終了、イベントループや基本的なキーボードやマウス入力がタダで手に入る。
- プレゼンター内に、直でボタンを描画したり、マウス入力を受けての更新といったコードを書くことも可能。
- ビューの基底クラスを継承すれば、ウィンドウのリサイズや再描画・デフォルトの描画などが手に入るし、GUI作成ツールを使ってレイアウトすることも可能になる。
- プレゼンターとビューだけだと、計算したデータをビュー内にしか保持していないので、電卓を終了したら結果が失われるが、モデルを継承すれば、計算結果を保存しておくことができる。モデルは、電卓の紙テープのようなものも表わせる(元の図参照)。
- ここまででは、モデルに対する操作は直接行われる。セレクションを実装すれば、紙テープの部分を選択できる。
- さらにコマンドを実装すれば、アンドゥやリドゥが可能になり、紙テープを逆向きに回せる。分散環境で、ネットワークをまたがって異なるユーザーがコマンドを実行することさえできる。
- 最後に、インタラクタを導入することで、計算の基数を変更したり、通貨を変更したりするメニューアイテムを追加できるようになる。野心的なプログラマーなら、手書きの数値入力用のインタラクターを実装することも可能。
- MVPの抽象化を継承することで、インタラクティブで、ドキュメント駆動で、埋め込めて、リンクできて、複数レベルのアンドゥができて、スクリプト化できて、リアルタイムにコラボできて、国際化されたビジネスアプリケーションが手に入るよ!!!!
クライアント/サーバー
- MVPのクライアント/サーバーへの応用。
- 典型的には、モデル、セレクション、コマンドがサーバー側、ビュー、インタラクターがクライアント側で、プレゼンターは両方のまたがる形。
- プレゼンターを置く比重によって、fatクライアントだったり、thin GUIアプリケーションだったりが有り得る。その分割は、境界を跨るプロトコルに依って決まる。
- あるいは、もっと洗練されたアプリケーションであれば、MVP全体が、どちらか片方に来ることも有り得る。たとえば、クライアント側のモデルが、ネットワーク越しの永続性を抽象化しているとかも有り得る。
クライアント/サーバーの色々なバージョン
- 既存のいろいろな具体例を見て、これらはMVPの各要素をサーバー側・クライアント側どこどこに配置したバリエーションだと考えられるね、ということを検討。とくに身のある内容でもないので省略。
- よくあるウェブアプリケーション5は、ビューとインタラクターがクライアント側、それ以外全部サーバー側に置いたバリエーションと考えられる。
- 分散アプリケーションをプログラミングするための7つ目の質問。「クライアントとサーバーの間で、どのようにアプリケーションを分割するか」
- このように色々な広範囲な例を当て嵌めることができるので、MVPモデルは基本的なアプリケーション開発のデザインパターンであると言える。
抽象化の利点
- MVPモデルによる区別に価値があることを論証。
- モデル/ビューの区別は、ビューの独立性をもたらす。例えば、異なる電卓レイアウトを、異なるビューとして、同一のモデルの上に実現できる。
- セレクション/モデルの区別は、モデルの独立性をもたらす。データ構造やファイルフォーマットをプログラムの他の部分から分離できる。また、永続性、リモートアクセス、共有などを可能とする。
- コマンド/セレクションの区別は、コマンドの再利用をもたらす。単一のコマンドを、ひとつ、複数、あるいは全体のセレクションに適用できる(それぞれの場合を特殊形として扱うのではなく)。コマンドはさまざまなアプリケーションから再利用することができる。
- インタラクター/ビューの区別は、入力の一般性をもたらす。アプリケーションロジックを変更することなく、異なるメニュー、ダイアログ、キーボードショートカット、ジェスチャ、あるいは手書き入力をサポートできる。
- プレゼンターからコマンド・インタラクターを分離することは、再利用可能なロジックをもたらす。例えば、科学計算の単位変換や、金融の複利計算を異なる文脈で再利用できる。
- これらによって、マルチプラットフォーム、複数標準での移植性、分散化、複数レイヤーでの分割が得られる。
要約
- Taligentはいろんな環境でMVPモデル使ってがんばってるよ!