【コラム】
Objective-Cを形容する言葉としてよく用いられるのが、シンプル、である。なるほど、シンプルというと聞こえがいい。しかし裏を返せば、機能が少ないということだ。
例えば、Objective-Cには抽象クラスがない。正確に言えば、抽象クラスという概念はあるが、それをサポートする言語上の機構はない。Cocoaのクラス階層で、ルートクラスになるNSObjectクラスは、間違いなく抽象クラスとして設計されている。だが、プログラム上で、NSObjectのインスタンスを作ることもできる。もちろん、何の役にも立たないインスタンスだが。
このとき、「役に立たないインスタンスならば、そのようなことができないように、言語で禁止すべきだ」という考え方もあるだろう。むしろ、近年の様々な言語の拡張の傾向を見ると、こちらが主流だろう。それに対して、Objective-Cの設計を見ていると、「そんなことはプログラマが気を付ければいい。そもそも、NSObjectのインスタンスなんて、誰も作らないだろう?」と、言っているように思えて仕方がない。この辺り、筆者には、愛すべきルーズさを感じるのだが。
さて。抽象クラスはないが、それと似たような機構がCocoaでは提供されている。いや、むしろ抽象クラスよりもスマートな仕組みと言えるだろう。クラスクラスタと呼ばれる機構である。
ここでは例として、文字列を取り扱うクラスを設計することを考えてみよう。文字列クラスはプログラミング中に頻繁に利用されるクラスであるから、特にパフォーマンスに気を付けて設計する必要があるだろう。そのために、異なる目的の文字列ごとに、特別なクラスを提供することを考える。例えば、C文字列を直接取り扱いたい場合は、その生のC文字列を保持しておくようにする。または、文字列がパスを表すならば、パス構造をキープしておきたい。
このようなクラス階層を実現するために、まず文字列クラスの基本となるクラスNSStringを定義する。その上で、特殊用途のために、NSStringクラスのサブクラスを作成する。このとき、NSStringクラスをパブリッククラス、そのサブクラスをコンクリートクラス、と呼ぶ。そして、この集合をクラスクラスタと呼ぶのだ。
Cocoaのクラスクラスタの面白い点は、コンクリートクラスが完全にプログラマから隠されていることだ。プログラミングでは、常にNSStringのインスタンスを作成することになる。すると、自動的に適切なコンクリートクラスが選択されるのだ。
次のようなコードで、NSStringを作成し、実際にできあがるクラスを調べてみよう。
str0は、リテラルによる文字列オブジェクトの作成。str1は、stringByAppendingPathComponent:という、要素を指定してパスを作成するためのメソッドを利用して作ったものだ。結果は、次のようになる。
このように、NSStringのメソッドを使って作成したが、実際はNSCFStringとNSPathStore2のインスタンスが作成されている。これらが、NSStringのコンクリートクラスとなる。
つまり、NSStringが抽象クラスである、と捉えることができる。コンクリートクラスを利用するときは、常にNSStringで定義されているメソッドを使うことになる。
これに加えて、クラスクラスタの面白いところは、サブクラスの存在が完全に隠されており、その選択がNSStringに任されていることである。実際、Cocoaプログラミングの初心者は、NSCFStringやNSPathStore2の存在にまったく気付かないだろう。非常にスマートな手法といえるだろう。
この仕組みは、デザインパターンの言葉を借りると、Factory MethodパターンとTemplate Methodパターンが合わさったもの、ということができるだろうか。面白いところは、FactoryもTemplateも、同じNSStringに見えるところである。
もう少し、クラスクラスタの実装を詳しく調べてみよう。Objective-Cでは、通常インスタンスの作成は、allocとinitという2つのメソッドによって行われる。allocでメモリを確保し、initで初期化を行う訳だ。
普通は、[[NSString alloc] init]というように、2つのメソッドを続けて呼ぶように書く。これを分解して、それぞれのメソッドで何が行われているか確認してみよう。
allocを呼んだ直後のオブジェクトと、init後のオブジェクトのクラスを表示している。結果は、次の通りだ。
allocではNSPlaceholderStringが返り、initの後ではNSCFStringとなる。このNSPlaceholderStringとは何者か?
NSPlaceholderStringは、NSStringのサブクラスであり、クラスクラスタの一部である。このクラスの役割は、名前が示す通り、NSStringクラスの一時的な代替物であろう。つまり、allocが呼ばれた時点では、どのNSStringサブクラスを作成するか決定してないので、NSPlaceholderStringを作る。そしてinitメソッドの種類によって、サブクラスが決定してまた新たに作成されることになる。
NSPlaceholderStringは、いわばNSStringクラスクラスタのための、Factoryクラスということになるだろう。
| トマトを食べれば痩せられる!? -京大ら、新発見の成分で肥満改善効果を実証 [21:00 2/10] |
| JAXA、液体シリコン中に残存する共有結合を観察 -大口径ウェハの実現に期待 [20:11 2/10] |
| NEDOなど、熱膨張が小さな樹脂複合材料ペレットの量産化に成功 [19:22 2/10] |
| 理研、一般顕微鏡を蛍光顕微鏡に強化できるアダプタを試作して性能を実証 [19:15 2/10] |
| 天の川のブラックホールが小惑星を飲み込んでいる - NASAが発表 [18:08 2/10] |
|
【連載】鉄道トリビア 第137回 山手線と京浜東北線から●●●が消えた!? [08:00 2/11] ライフ |
|
JRグループ、「周遊きっぷ」を見直し - 19の周遊ゾーンが3/31で販売終了に [07:30 2/11] ライフ |
|
「青春18きっぷ」春季用は2/20発売 - 夏季用・冬季用の発売は現時点で未定 [07:30 2/11] ライフ |
|
【ハウツー】炊飯器でつくるチャーシューが簡単すぎ、しかもおいしい! [07:00 2/11] ライフ |
|
【連載】出社前に。日常生活ですぐに使える! 英語クイズ 第118回 「どうぞお話しください、あなたが話す番です」ってなんて言う? [07:00 2/11] ライフ |