クラスを拡張してメソッドを増やして行くと、System Browserでのメソッドの一覧性が悪くなってくる。たとえば、今までにMyMorphのクラスで定義したメソッドは14個程度だが、ペインに入りきらない状況になっているだろう。
Smalltalkでは、メソッドの分類を行うためにプロトコルと呼ばれるものを用意している。プロトコル自体はプログラムの動作に何の影響もなく、単にプログラマにメソッドの分類方法を提供しているだけのものだ。とはいえ、プロトコルがなければ数十ときに数百に上るメソッドを持ったクラスのメンテナンスがとても面倒なものになってしまう。今回のチュートリアルでは、プロトコルによる分類について学ぶ。
まずプロトコルについて。以前、クラスの分類にクラスカテゴリを用いることを述べたが、プロトコルも同様のものである。座標をあらわすPointクラスを例にあげて説明しよう。
座標をあらわすPointクラスには様々なメソッドが定義されており、座標自身の情報の設定や取得に加えて、座標同士の演算や比較、変換や便利な機能など、およそ100のメソッドがある。
Point methods size. "99"
プロトコルによって多数のメソッドを分類する。Pointクラスには以下のようなプロトコルがある。
Point protocols joinUsing: String cr. "'-- all -- copying *Fuel accessing private point functions printing self evaluating transforming interpolating testing geometry truncation and roundoff polar coordinates extent functions converting truncation and round off comparing arithmetic'"
先頭の’– all –‘は、全てのメソッドの一覧を得る際の擬似的なものであり、アスタリスクで始まるプロトコルは他のパッケージに属しているものを表す。その他は、Pointクラスにおけるさまざまな役割や機能を表すプロトコルとなっている。
どのメソッドをどのプロトコルに配置すべきかはクラスの設計者が決定しなければならない。このあたりの判断はなかなか難しい。既存のクラスを参考にしながらどのプロトコルに配置するかを決めていく。例えば、printOn:というメッセージが他のクラスではどのようなプロトコルで定義されているか調べるには以下のようにする。
SystemNavigation default browseAllImplementorsOf: #printOn:
printOn:を定義しているクラスの一覧が表示され、クラス名の右側の丸括弧の内側に定義されているプロトコル名が表示される。
これを見ればprintingプロトコルで定義されているのがわかる。
最近のブラウザでは親クラスの配置を参考に、自動的にプロトコルへ振り分けてくれる機能を持っている。SystemBrowserのプロトコルペインで右クリックすると、categorize all uncategorizedというメニュー項目が現れるのでクリックすると、プロトコルに分類していないメソッドを自動的に分類してくれる。
メニューを選んで分類が終わると以下のようになる。
おおむねそれらしく配置されているが、handlesMouseOver:がevent handlingではなく、recategorizedに分類されているのは違和感がある。このような場合には手動で分類する。handlesMouseOver:をドラッグしながらevent handlingでドロップすれば良い。
なお、どこにも定義されていないような自分メソッドを作った場合、既存のプロトコルで適切なものがなければ自分で作成することになる。新たにプロトコルを作成するには、プロトコルペインでAdd protocol…を選べば良い。
メソッドはどのプロトコルに分類したからといって実行性能に影響するわけではない。プロトコルはクラスの開発者や利用者がメソッドを探しやすくするための工夫である。Smalltalkerは「こんな機能(メソッド)ないかな?」と思ったときにプロトコルを手がかりにメソッドを探すことが多い。うまくメソッドを分類できれば時間短縮につながるので、ひと手間かけてプロトコルに分類することには価値がある。
(番外編おわり)