yojikのlog

yojikのブログです

[tech]GUI-MVCとWeb-MVCの違い

一部でMVC議論が流行っていたので、自分のためにSmalltalk由来のMVC(以下、一般化してGUI-MVCと呼びます)はWeb-MVCとどう違うか? という点についてまとめて見ました。突っ込みは歓迎。
あと本稿ではドメインモデル貧血症批判とかは全く盛り込まない。それは少し違うレイヤーの話なんです。

0. VCは大抵の場合、緊密に結びついたペアである

GUI-MVCではView-Controller(以下VCペア)は不可分のペアだとされています。情報の入力(および制御)と出力ですから、お互い強く依存するのはあたりまえですね。MicrosoftのMFCとかJavaのSwingではVCはひとつのコンポーネントとして扱っています(Document-Viewパターンとも呼ばれます)
ただ、この点についてはWeb-MVCでもそんなに変わらないかも。

1. GUI-MVCのView-Controllerペアは単位が違う

先ほど述べたようにGUI-MVCのVCペアは、ある種のコンポーネント、画面の部品です。リストデータ(Model)を表示するListView+Controllerとか、表形式のデータを表示するTableView+Controllerとか。WebではMVCは一画面ごとにVCペアを割り当てたりしますが、GUI-MVCではもっと細かい部品の単位でVCペアが存在します。

これはWeb-MVCとはかなり違うところです。Webの世界では「一画面」より小さい画面部品は実質存在しないから同等なのだ! みたいな頓知解答は、この場合不適切ですね。

2. GUI-MVCのVCペアは入れ子になる

TableView+Controllerが、実はTableHeaderView+Controllerと複数のTableRowView+Controllerで構成される*1、といった具合にVCペアが、より複雑なコンポーネントの部品になることがあります。

リストやソースビューアのような単純なコンピーネントから、システムブラウザのような複雑な部品が生まれたりします。つまり分割統治の見本のような形になりますね。(分割統治にはいろいろな切り口があるんです)

ただし入れ子になったVCペアとModelの関係については非常に気になるところです。VCペアが入れ子になった場合、Modelも入れ子になっているのか? それともModelとVCペアの構造は別々なのか。ここは確かに問題になるところでありますが、今回の議論とは別件なので分離します

3. GUI-MVCのVCペアは汎用コンポーネントを目指す

Web-MVCではModelの再利用性ばかり宣伝されますが、GUI-MVCではVCペア自体の再利用性も重視されます。コンポーネントなんだから再利用したいですよね。
VCペアを毎回特定のモデル向けに実装するのではなく、VCペアが自分に適合するインタフェースを持つモデルだけ扱うようにします。いちいちVCペアを継承して実装したりせずに再利用可能になります。Smalltalk界隈ではプラガブルMVCと呼ばれるものです。

ただしModel自体の再利用性を高めるという当初の目的には矛盾しそうですね。この問題に対象するためにSmalltalk界隈ではMMVCと呼ばれるMVCの改良版のパターンが考案されました。Modelを、ApplicationModelとDomainModelに分割するという方式です。プラガブルMVCの実現にはMMVCが不可欠というのが俺の理解です。(あってるだろうか?)。

JavaのSwingでも、例えばJTableはTableModelインターフェースを実装したモデルを要求します。開発者は、TableModelを実装したApplicationModelを開発し、それがDomainModelにアクセスするというやり方で対処しています。つまりAdapterパターンですね。

4. GUI-MVCではObserverパターンを利用することが多い

これはみんな知ってることだから長々書きませんが、、Modelの変更をViewに反映させるために、Observerパターンを利用することが多いです。また複数のVCペアから構成されるような複雑なコンポーネントが矛盾なくリアルタイムで情報を表示させるためには、ObserverとかMediatorパターンをフル活用する必要があります。(GoF本にそういう例が載ってましたね)

結論

と、長々述べましたがWeb-MVCとGUI-MVCは全然違うので、そのパターンが必要となる制約条件や、得られるメリットも全く違うということです。

だからといってWeb-MVCはクソだなーと言うつもりはあまりなく(個人的には好きでは無いですが)、Request-Dispath-Process-Templateパターンとか、そんな名前にすればよかったんだと思います。あんまりキャッチーな名前じゃないから使う人が少なかったかも知れませんが。

*1:これは架空のライブラリを想定しています