Common Lisp クックブックもぼちぼちやってます。
2006-04-17
■[Objective-C] Objective-Cにおけるクラス命名パターン
クラス命名のアンチパターンにけっこう反応があるようで、調子に乗ってアンチではないパターンを主にObjective-C (Cocoa) を例に挙げて、まとめてみる。 ただ公式に命名パターンがあるわけではなく、あくまで個人的な見解です。
データ構造
最初の基準は、オブジェクトをデータ構造とみなすかそうでないか。 例えば Array や Font ならデータ構造と考えることができるが、 Scanner, Parser, Compiler などはデータ構造とは見なさない。 これらのデータ構造そのものではない、データ構造を使って処理を行うオブジェクトには、接尾辞に -er をつける。 このような他のオブジェクトに作用するオブジェクトのクラス名を考えるには、そのオブジェクトの役割よりも作用するオブジェクトとの関係を考えるとわかりやすい。
Manager
アンチパターンにも書いた、ついつけたくなるクラス名だが、Cocoaでも NSFileManager や NSUndoManager などのクラスにつけられている。 各クラスの主な役割はオブジェクトの集合や外部ストレージへのアクセスで、ものによっては単なるラッパーに近い。 また、どれもアプリケーションプロセス一つにつき一つのインスタンスを共有している。 つまりデータへのアクセスが主な処理で、一つしかインスタンスを必要としない、なくても問題がないクラスがManagerになる。
Managerに似た例としてCenter (NSNotificationCenter, EOObserverCenter) がある。 インスタンスを共有する点は同じだが、こちらは処理が異なるのと、中央集権的にリクエストを受け取るからCenterになっている。
またデフォルトではインスタンスが一つでも、複数のインスタンスを使う可能性がある場合は Manager 以外の名前、Store, Group, Set などがつけられている。 そんなにたくさん管理職はいらない、という無言の抗議かもしれない。
Store, Group, Set
どれも、あるオブジェクトの集合を扱うクラスにつけられている。 また直前で触れたように、そのクラスのインスタンスを一つだけ共有して使うような場合はManagerになることが多い。 それぞれの使い分けはこんな感じ。
- Store
- オブジェクトの集合のデータベース (メモリか外部ストレージにオブジェクトを保存) となる場合。SessionStoreなど。
- Group
- オブジェクトの集合へのアクセスを行うが、データベースにはならない場合。ModelGroup, DisplayGroupなど。
- Set
- オブジェクトの重複を許さないGroup。CharacterSetなど。
もし複数のクラスのインスタンスを扱うことになる場合は、別の名前を考えるべき。
Handler
Cocoaで言うHandlerとは、
- とっかえひっかえ可能で、
- 共通のインターフェース (メソッド) を持ち、
- 必要なときに他のオブジェクトから呼ばれる
クラスにつけるものとなっているらしい。 わかりやすい例にWebObjectsの WORequestHandler というクラスとそのサブクラス数種類があって、handleRequest メソッドでHTTPリクエストを受け取って処理を開始する。 ただしHandlerはDispatcherではなく、どのハンドラを使うかは別のオブジェクトが決定する (ハンドラはURL中で指定できる) 。 XMLなどのパーザで使われるハンドラとだいたい使い方は同じ。
これは委譲 (Delegate) と言ったほうが通じやすいと思う。 それなのにDelegateと名前がつかないのは、委譲する内容がアプリケーションにとって必須かどうかが基準になっている様子。 アプリケーションからの委譲用メソッドの実装が必須で、デフォルトの委譲用クラスが用意されている (しなければならない) なら、委譲先オブジェクトのクラス名はHandlerになる。 必要があればユーザ側で実装してくれということなら、委譲用クラスの名前はDelegateとつけることが多い。
Description
CocoaとWebObjectsとSmalltalkには、 ClassDescription というクラスがある。 名前の通りクラスに関する情報を扱うクラス。 だいたいクラス自体がDescriptionなのだから、意味がわかりづらいクラスだと思う。 それでもわざわざ別にしているのは、Classクラスのみにすべて詰め込むには情報が多いため、わかりやすいように分割しているのではないかと思う。 CocoaではClassとClassDescriptionのインスタンスは1:1の関係だし、SmalltalkではClassDescriptionはClassのスーパークラスになっているから。
またWebObjectsのDBライブラリをCocoa風にしたCore Dataには、Entity-Relationshipを表す NSEntityDescription, NSRelationshipDescription などがある。 もともとCocoaのNSClassDescriptionがClassとEntity-Relationshipモデルを結び付けて扱うクラスだったので不自然ではないが、つける必要もない。 WebObjectsでは EOEntity, EORelationship とすっきりしている。 おそらくObjective-Cの名前空間の都合上、他のクラスに似た名前になる可能性があった/ありそうだからDescriptionをつけたのかと思うけど、深読みかな。
Controller
CocoaのGUIフレームワークはMVCを柱に据えているので、ウィンドウと通信するクラスにControllerとついていたりつけたりすることが多い。 Controllerの名のつくクラスの役割は、ユーザがGUIで行う操作を実装することと、ユーザがGUIで操作している状態を保持すること。 特にCocoaバインディングで使われる NSObjectController, NSArrayController がMVCのC (Controller) に相当する。
ただしCocoaバインディングが登場する以前からウィンドウを管理するクラスに NSWindowController, そのほか NSDocumentController などのControllerクラスがあり、こちらはGroup/Setに近い意味になっている。 またウィンドウやボタンの各種イベントを実装するクラスの名前をControllerとつける慣習もあって、以上を合わせるとControllerの意味が三つも混在してしまっている。
ControllerもManagerと同じく意味が漠然としている上、MVCが十分に認知されたので、MVCを明示的に前面に出すような場合以外はつけるべきではない。つけるな危険。
個人的には、GUIフレームワーク以外には使ってはいけないと思っている。 実際にCocoaの多くのフレームワークの中でも、特にMVCを標榜するフレームワークの中でも、GUIフレームワーク以外にはまったく使われていない。
Context
一見さんお断りの雰囲気を醸し出すこの名前、辞典的に言うと「あるとき、あるオブジェクト間で発生したイベント内でのみ有効な処理を行うオブジェクト」で、要約すると「流れを扱うオブジェクト」で、端的に言うと「セッション」に近い。
Contextの例は、CocoaやWebObjectsよりもSmalltalkなどの言語処理系のほうがより一般的かと思う。 Smalltalkではメソッド内でthisContextという疑似変数を参照すると、MethodContextオブジェクトを取得できる。 MethodContextはメソッドの実行を行うオブジェクトで、
- 呼び出し元のMethodContext
- 実行するメソッドオブジェクト (バイトコード)
- レシーバ
- メソッドに与えられた引数リスト
などの情報を持つ。 Smalltalkでは例外が発生すると、発生元のMethodContextをたどってすべてのMethodContextをデバッガでリスト表示する。 これでどの順序でメソッドが呼ばれたのかがわかるし、どのメソッドにどんな引数が渡されたのかもすべてわかる。 例外が発生してもMethodContextはすべて生きているので、一旦メソッドを修正して例外が発生する前のMethodContextから再実行すれば、何もなかったようにメソッドの実行が進む。
アンチパターンにも入れたように、ManagerやControllerと同じく意味が漠然としていて範囲が広すぎるため、何だってContextになりうる。 ということは、まず別の言葉で言い替えることができる。 もしContextを使う場合は、Contextとつくすべてのクラスが同じ概念で処理を行うようにし、どんな大きなアプリケーションやフレームワークでも数種類に留めるべきだと思う。
でもContextがわかりづらい本当の理由は、「文脈」ではないContextの意味をストレートに表した和訳がないからだと思う。 "object" と同じく、英語圏の人には馴染んだ概念なのかもしれない。 英英辞典を引いてみると "circumstances in which sth happens or in which sth is to be considered" とあり、このまま和訳すると「状況下」になるが、どうもピンとこない。 これは、Contextは日本語で言うなら、期間を表す「中 (ちゅう) 」ではないだろうか。 処理中とか起動中とか、身近なところなら仕事中とか、授業中とか。
参考書籍
ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集
- 作者: ケントベック,Kent Beck,梅沢真史,皆川誠,小黒直樹,森島みどり
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2003/03
- メディア: 単行本
- 購入: 6人 クリック: 83回
- この商品を含むブログ (53件) を見る
Smalltalkでプログラミングをする上でよくある状況をまとめた本、イディオム集のような内容で、半分は (メソッド・インスタンス変数の) 名前をどうつけるかについてのヒントの本。 クラスの命名についての記述もあるけど、継承が多いというSmalltalkの事情が前提としてあるので、そこは差し引いて。 命名に関してはSmalltalk以外の言語にも十分なヒント・指針になると思います。
