何故、CocoaのMVCとレガシーなMVCはアーキテクチャが違うのか?

MaciPhoneSDKが提供しているCocoa*1で一番気になるのがMVC。何故、CocoaMVCは、レガシーなMVCと違うアーキテクチャを採用しているのか。
気になったので、考えてみた。

レガシーなMVC

レガシーなMVCの最大の目的は、Modelを再利用するアーキテクチャを提供すること。
このアーキテクチャでは、ViewやControllerはアプリによって、変更されることが前提になっている。そのため、ViewやControllerの再利用については言及されていない。
そのため、真面目にこのアーキテクチャで実装すると、ViewはModelとControllerに依存してしまい、Viewの再利用性は失われる。
[特徴]

  • ModelはViewにもControllerにも依存しない。*2
  • ViewはControllerとModelに依存する。
  • ControllerはViewとModelに依存する。

CocoaMVC

CocoaMVCの最大の目的は、ViewとModelを再利用することに加え、ViewとControllerをプログラムレスで開発するアーキテクチャを提供すること。
CocoaMVCでは、ViewとModelの間にControllerを位置付けることにより、Viewの再利用性を確保する。ここで言うViewの再利用は、一度作ったViewは他のアプリにも使いまわせるという意味。もちろん、アプリの見た目が変われば、レガシーなMVCと同様、Viewを作り直す必要がある。
また、CocoaのControllerはMediatorパターンが採用されており、ControllerはViewとModelの間でがんばらないといけない。これにより、ViewとModelは完全に分離され、再利用性が高まる。このControllerをプログラミングにより実現すると本当に再利用性の欠片もないControllerができてしまうことになる。
しかし、Cocoaでは驚くべきことに、バインディング技術とInterface Builderを利用*3することにより、Controllerをプログラムレスで実現することができる。つまり、Controllerには再利用性がないが、Cocoaではプログラミングするという労力を省くことができる手段を用意している。
[特徴]

  • ModelはViewにもControllerにも依存しない。
  • ViewはControllerに依存する。
  • ControllerはViewとModelに依存する。

レガシーなMVCの実装例

では、レガシーなMVCを実際に実装する場合を考えてみる。
Viewの実現には、Widget*4と呼ばれるUI部品の集合を使うとする。このWidgetはリストやラベル、ボタンなどの種類があり、CocoaのViewと同様に再利用可能なものとなる。このWidgetにはWidgetの振る舞いを決定するWidget用コールバック関数を登録することができ、このコールバック関数がMVCで言うところのControllerに相当する。
WidgetだけはModelからの要求を受けることができない。そのため、Widgetを管理し、かつ、Modelと連携可能なViewを別途定義する。ModelとViewの連携はObserverパターンにより実現する。Cocoaの場合は、View自体がWidgetであり、Modelと連携できるように定義されているため、別途、ViewやModelを定義する必要はない。
更に、ViewにはModelからの要求を受信すると呼ばれるView用コールバック関数を登録できるようにする。このコールバック関数で、WidgetAPIを呼び出し、UIを変更する。View用コールバック関数もWidget用コールバック関数と同様にMVCで言うところのControllerに相当する。
このWidget用ControllerとView用Controllerを一つのControllerとして考えるとCocoaMVCと同じアーキテクチャになる。
Cocoaでは、ViewはWidgetの機能も持っており、ViewとModel間のやりとりはCocoaバインディングで定義されている。そのため、CocoaではView用Controllerに相当する機能を実装しなくてもViewとModelの連携を実現できる。そうは言っても、Modelから通知された情報をViewが理解できる情報に変換したい場合がある。それを解決するために、CocoaのControllerでは、Modelから通知された情報をViewが理解できる情報に変換するクラスを登録する仕組みが用意されている。

[特徴]

  • ModelはViewにもControllerにも依存しない。
  • View(Widget含む)はControllerに依存する。
  • ControllerはViewとModelに依存する。

結論

レガシーなMVCCocoaMVCは違うアーキテクチャに見えるが、実装レベルにまで落とすと、両者とも同じレベルになり得ることが分かった。
CocoaMVCはレガシーなMVCをより実装に近い形でモデリングしなおしたものと言えそうだ。

*1:iPhoneの場合はCocoa Touch

*2:ModelからControllerとViewへ出ている要求は、Observerパターンにより、Modelとは非依存にできる

*3:バインディング技術とInterface Builderの関係については、いずれ、別エントリーで見解を述べる

*4:GTK+、Motif、AWTなど