前回は、Mediatorパターンの概要を紹介した。今回からは、Cocoaフレームワークの中で、このパターンを利用して解釈できるものを紹介しよう。
取り上げるのは、Cocoaアプリケーションの中でも中心的な概念になる、コントローラだ。
MVCの「C」
ある程度複雑なアプリケーションを設計する際に、言語やプラットフォームを問わず、広く使われている重要な概念がある。MVCアーキテクチャだ。アプリケーションの構成要素を、M(モデル)、V(ビュー)、C(コントローラ)の3つに分割するという考え方だ。Cocoaも、このアーキテクチャを全面的に採用している。
MVC自体は一般的な考え方であり、それをどのように採用しているかは、言語やフレームワークによって微妙に異なる。Cocoaの考え方では、コントローラが最も重要となる。というのは、MVCの3つの構成要素のうち、ビューはCocoaフレームワークが提供する。それをそのまま使えば、ほぼ問題ない。モデルは、書類を保存するタイプのアプリケーションでは重要になる。だが、ユーティリティのように編集対象がないアプリケーションでは、必要なくなる。
ということで、Cocoaアプリケーションを作るときは、まずコントローラから作り始めることになる。ビューやモデルは、他のアプリケーションでも再利用できるように考慮して設計すべきだが、コントローラはそのアプリケーションの専用のものになるだろう。主となるビジネスロジックも、コントローラに実装することが多い。
CocoaのMVCでは、コントローラがアプリケーションの多くの役割を担う。これは、コントローラ万能主義とも言えるかもしれない。
Mediatorとしてのコントローラ
そのCocoaのコントローラだが、GoFのデザインパターンを使って解釈してみると、MediatorパターンにおけるMediatorの役割を担っている、と捉えることが出来るだろう。
Cocoaフレームワークは、ビューとなるクラスはたくさん用意している。ビューはユーザインタフェースとなる部品で、ウインドウ、ボタン、スライダー、ポップアップメニュー、スクロールバー、テキストフィールドなどがある。だが、これらのほとんどは、互いに独立して動作するように設計されている。もちろん、再利用性を高めるためだ。
実際にアプリケーションを作成するときは、これらの部品を連携させて動作させる必要がある。それを行うのが、コントローラだ。つまり、ビュー同士の働きを、仲介する立場にある訳だ。Mediatorパターンの言葉を使えば、コントローラはMediator、ビューはColleagueと言うことが出来るだろう。
ColleagueからMediatorへのアクセスの汎用化
では、MediatorとColleagueとの間、つまりコントローラとビューの間のやり取りはどうなっているのだろうか。ビューを汎用的な部品とするには、ここの結びつきは出来るだけ弱くしておきたい。
まず、MediatorからColleague、つまりコントローラからビューへのアクセスを考えてみよう。この場合は、コントローラをビューにあわせて作り込むことになる。ビューは、そのクラスによって、独自のAPIを提供している。ボタンならボタンのAPI、スライダーならスライダーのAPIがある訳だ。これらを、アプリケーションの目的にあわせて、コントローラが利用する。コントローラはアプリケーションごとに専用になるので、ここでは汎用化は必要ない。この実装を行うのが、アプリケーション作成の中心となるだろう。
問題は、ColleagueからMediator、つまりビューからコントローラへのアクセスだ。これがコントローラごとに変わるのではいただけない。ビューを汎用的な部品にするには、このアクセスも汎用的にしたい。
Cocoaで使われているのは、ターゲット/アクションの考え方だ。それぞれのビューでは、ユーザの操作に応じて、「アクション」を起こす。アクションの発生のさせ方は、インタフェースによって異なる。たとえば、ボタンであれば、ボタンをクリックしたときに発生する。スライダーであれば、ノブを動かして、表している値が変更されたときに発生する。
このアクションが発生したときに、ユーザが期待する、そのインタフェースが行うべき処理を行うのだ。もっと具体的に言えば、ビューの操作によって、コントローラのメソッドを呼び出し、そこで実装されているビジネスロジックを実行するのだ。
では、ビューはコントローラのどのメソッドを実装するのか。これは、コントローラがあらかじめ、ビューに対して実行してほしいメソッドを登録しておく、というスタイルになっている。このメソッドのことを、アクションメソッドと呼ぶ。
アクションメソッドとして登録出来るメソッドには、1つだけ条件がある。それは、引数として、id型の変数を1つ取ることだ。たとえば、次のようなメソッドがアクションメソッドとして使用出来る。
List 1.
- (void)actionMethod:(id)sender;
アクションメソッッドになるための条件は、これだけだ。あとは、どんな名前のものでもいい。何か特定のクラスを継承して、そこに含まれるメソッドをオーバーライドして、などとしてやる必要はない。この考え方を、ターゲット/アクションパラダイムと呼ぶ。詳しくは、本連載の第4回も参考にしてほしい。
これが、ビューからコントローラへのアクセスとなる。Mediatorパターンの言葉を使えば、ColleagueからMediatorへの呼び出しは、汎用的なものになっている。Mediatorがあらかじめ継承しておくべき、AbstractMediatorのようなクラスは存在しない。従って、この結びつきは弱いと言えるだろう。
次回は、このコントローラをさらに汎用化させたものについて紹介しよう。MediatorとColleagueの結びつきは、極限まで弱くなる。