Nov 15, 2012

MVCパターンの適用限界を考える(4)

1つ前のエントリーで、いわゆる"Model 2"がMVCパターンの用語で説明されるようになったことが、人々のMVCの理解をバラバラにする原因になった、と書いたが、そのことは、前エントリーの参考リンクの先のページでも見られるように、多くのWebページで触れられていることでもあるが、筆者はむしろ、いわゆるGoF本に書かれているMVCの説明が最大の混乱の元だと思っている。"Design Patterns: Elements of Reusable Object-Oriented Software"(邦訳タイトルは「オブジェクト指向における再利用のためのデザインパターン」)、いわゆるGoF本の§1.2にある以下の記述がそれである。

MVC consists of three kinds of objects. The Model is the application object, the View is its screen presentation, and the Controller defines the way the user interface reacts to user input.

MVC also lets you change the way a view responds to user input without changing its visual presentation. You might want to change the way it responds to the keyboard, for example, or have it use a pop-up menu instead of command keys. MVC encapsulates the response mechanism in a Controller object.

A view uses an instance of a Controller subclass to implement a particular response strategy; to implement a different strategy, simply replace the instance with a different kind of controller. It's even possible to change a view's controller at run-time to let the view change the way it responds to user input. For example, a view can be disabled so that it doesn't accept input simply by giving it a controller that ignores input events.
(注:ここでは"disabled"はボタン等が操作できない状態のことを指す)

GoF本の1.2節を開いてまず目を引くのは、図にControllerが無く、1つのModelと複数のViewのみで構成されていることである。上記の引用文にある通り、これは、ControllerがViewの一部として扱われているからである。
MVCの最大の目的はPresentation logicとBusiness logicの分離による安定性の向上(変化する部分と変化しない部分の分離)である、というのはOriginal MVCから一貫した理念であるが、システム全体を(Controller抜きで)ViewとModelに分離すると書くことによって、それを最大限に強調しているのである。これはMVCの本質をわかりやすく表していると思う。

しかし、それから少し読むと違和感を覚えるのが、ユーザー入力を受けたViewがどう振る舞うかを、そのViewのControllerが決める、という記述である。このようなことは、Original MVCには書かれていない。また、Original MVCに書かれている、ControllerからViewへのメッセージ送信についても、GoF本には明確な記述が無い。
もしこれが、Original MVCのControllerの定義にある

Conversely, a view should never know about user input, such as mouse operations and keystrokes. It should always be possible to write a method in a controller that sends messages to views which exactly reproduce any sequence of user commands.

と矛盾しないとすれば、ユーザー入力がViewからControllerへ伝搬されるというのは、"views which exactly reproduce any sequence of user commands"の部分を拡大解釈したものであり、Controllerは入力デバイスのドライバーやウィンドウシステムの役割のみを担うものとしていると解釈するのが妥当であろう。
早い話が、JavaのSwingやQt, GTKなどのイベントドリブンなツールキットを用いて実装されるGUI全体をViewだとしているのである。
図にすると次のようになる。

Class diagram of MVC in the GoF design pattern book
図5-1: GoF本のMVCのクラス図(静的構造図)

Communication diagram of MVC in the GoF design pattern book
図5-2: GoF本のMVCのコミュニケーション図(動的構造図)

ポイントとしては、Viewがユーザーイベントの配信を制御することが可能になっており、Original MVCではV-C間の関連におけるControllerの役割だったものの大部分がViewに移動している。また、ViewはControllerより先に存在する前提であり、Viewが表示されていない状態からControllerがView上にメニュー画面の表示を要求するようなことは想定されていない(Swing等のGUIフレームワークを使えば、最初からGUIが何か表示されているのが普通だから、想像は難しくない)。

ViewとControllerの関連の向きがOriginal MVCと逆であることをわかりやすくするため、Controllerのデバイスドライバー/ウィンドウシステムとしての役割を省いたのが、次の図である。

Communication diagram of MVC in the GoF book
図5-3: GoF本の記述に沿ったMVCのコミュニケーション図(簡略化版)

このMVCのモデル(以下、GoF MVCとする)は、GoF本のテーマにはよく乗っており、同書の以下のデザインパターンが使われていると書かれるのは非常に納得できる。
・Observer
・Strategy
・Composite
・Factory Method
・Decorator

Observer patternが使われることは言うまでもないが、Modelが変化すると、observerとして登録されている全てのViewに何か変化があったことが通知されることを実現するのに使われている。
Observer pattern in GoF MVC
図5-4: GoF MVCにおけるObserverパターン

Strategy patternは、ユーザー入力に対するViewの振る舞いを決めるControllerが、Viewのインスタンス毎に切替可能であることを実現するのに使われている。多くのGUIフレームワークでは、イベントのコールバック関数(リスナー)が動的に登録可能であることに相当する。ここではControllerがViewの一部なのは、上述の通りである。
Strategy pattern in GoF MVC
図5-5: GoF MVCにおけるStrategyパターン

Composite patternは、View同士が包含関係になり、親Viewが受けたイベントを、内包するViewに伝搬することにより、複合ViewをViewと同じように扱うことを可能にするのに用いられている。GUIフレームワークでは、例えばコンテナの中にコンテナを含めることに相当する。Original MVCの"The Model-View-Controller (MVC) Its Past and Present"のP-9にある"Tool as a composite"も、大体同じような内容である。
Composite pattern in Gof MVC
図5-6: GoF MVCにおけるCompositeパターン

Factory Methodパターンは、各Viewのdefault controllerを得るのに用いられる、とされる。これによって具象Viewから具象Controllerへの依存を無くすことができ、例えば具象ViewがControllerのいずれかのサブクラスを指定してインスタンスをcreateする必要が無くなる。GUIフレームワークでは、起動時のパーツの配置や初期設定をアプリケーションのmainクラスがまとめて保持することが、強いて言えばこれに相当するだろうか。(世の中にはあるのかも知れないが、筆者はあまりControllerのFactoryというのを見たことがない)
Factory Method pattern in GoF MVC
図5-7: GoF MVCにおけるFactory Methodパターン

Decoratorパターンは、Viewのサブクラスに共通する機能の追加を、それぞれのサブクラスを新たに作ることなく、委譲を用いて実現するのに用いられる。GUIツールキットでは、例えばGoF本には、各コンポーネント(クラス)にスクロール機能を追加する時に用いられると書かれている。
オブジェクト指向の経験則として、既存クラスの拡張や既存クラスへの機能追加は、派生クラスを作成するより、AdapterやDecoratorなどを使った委譲によって行う方が良いことが多いと言われることがある。小規模な機能拡張で一々、それぞれの機能の有無毎に派生クラスを作成するのは面倒で非効率であることを考えば、納得できる。
Decorator pattern in GoF MVC
図5-8: GoF MVCにおけるDecoratorパターン

世の中にC→Vの関連が無くV→Cの関連があるMVCパターンの図が存在するのは、GoF本の記述が原因であろう。
また、MVCのデザインパターン的な側面を語られる時は大体、V-C間の関連はViewからControllerへの関連であることも興味深い。V-C間の関連がControllerからViewである、Original MVCに則してGoFのデザインパターンが語られることはほとんど無い。
これは、既存の多くのGUIフレームワークに当てはめてMVCを解釈するには悪くないし、MVCが将来そのような考え方に置き換わっていくのは必然なのかも知れないが、それは筆者にはどうしてもMVCの拡大解釈であり、MVCとは別の名前を付けるべきだったように思える。

GoF本に書かれているMVCは、極端に言えば、Controllerが無くても動作可能なMVCアーキテクチャーである。ウィンドウシステムがミドルウェアに、データモデルや表示系アプリがアプリケーション層にあれば、アプリケーション層だけを見るとControllerが存在しない。
実際、GoF本には、何もしないControllerをViewに与えることによって…という記述があるし、Original MVC的にはViewからのModelの更新はあり得る訳だから、システム全体としてController無しでMVCパターンを実装することも可能だということになる。

ControllerはViewとModelの橋渡しに過ぎず、MVCモデルはViewとModelが主役、というのはMVCの本質であり、それを強調することは悪いことではないと思うが、Controllerの役割やC-Vの関連についてほとんど触れられないのは如何なものであろうか。MVCの本質でなくても、Controllerの位置付けはMVCの必須構成要件である。
オブジェクト指向的に考えると、Controllerのオブジェクトは本質的には不要なので、どの方向から考えても結局はControllerの責務は最小にされるべきだという結論になるからだ、としても、ControllerがViewの一部であるように表現してしまうのは、MVCの説明としては問題があるのではないか。

筆者は、GoF本の記述は、テーマ的にMVCについて触れない訳にはいかないから、同書の内容、あるいは現存するGUIフレームワーク(筆頭著者のErich Gamma氏はJavaとの結び付きが強いからAWTだろうか)と整合する為に、このようにされたのだと考えるべきものだと思う。

See more ...

Posted at 17:16 in PC一般 | WriteBacks (0)
WriteBacks