言語仕様とオブジェクト指向

2008年11月27日(木)
荻原 剛志

実際の継承の例

 図2-1はJavaのインタフェース定義で、文字列を返すメソッドdescriptionだけからなるDescriptionというインタフェースを定義しています。図2-2はこのインタフェースを採用するクラスFaceの定義、図2-3はクラスTimeOfDayのJava版で、コンストラクタで時刻の設定ができます。図2-4はクラスTime12の定義で、スーパークラスとしてTimeOfDayを継承すると同時にインタフェースDescriptionを採用しています。

 このように定義したクラスFaceとクラスTime12の間には直接の継承関係はありませんが、どちらもインタフェースDescriptionを採用しています。インタフェースは実装を伴わないため、それぞれのクラスでメソッドdescriptionを実装しなければなりません。

 この2つのクラスを使った例を図2-5に示します。Javaではインタフェースを型として指定できます。Time12、Faceの各インスタンスもメソッドdescriptionのみを使う限りはDescription型の同じ変数に代入して扱えます。通常の継承関係と同様に、ポリモーフィズムの恩恵にあずかれるわけです。実行例は図2-6の通りです。

デリゲート

 インタフェース継承で継承されるのはインタフェースのみなので、それぞれのメソッドは各サブクラスで実装する必要があり、今度は実装コードの共有が難しくなるという問題が発生します。この問題を軽減する方策の1つとしてデリゲートの考え方を紹介します。

 デリゲート(またはデリゲーション)は日本語では「委譲」などの訳語が当てられることがあります。あるオブジェクトがメッセージを受け取った時、その処理を別のオブジェクトに任せる仕組みや手法がデリゲートです。

 簡単な実現として、インスタンス変数で別のオブジェクトを参照するようにしておき、必要に応じてそのオブジェクトに処理を依頼する方法が考えられます。原理的にはこれで十分です(図2-7)。そのほか、言語システムの機能を利用して、インタフェースで決められたメソッドの処理を一括して任せる方法や、自身が処理できないメッセージをすべて転送する方法なども考えられます。

 継承もデリゲートも、対応できない処理を別の個所の実装に任せるという点では同じです。しかし、継承関係はプログラムを記述した時に決まるので、サブクラスで定義されていない操作が求められると、常に同じスーパークラスのメソッドで処理が行われます。デリゲートの場合、委譲先となるオブジェクトを変更することで、処理内容を動的に変更することができます。

 例えば、ウィンドウを表すオブジェクトにデリゲートを指定できるようにしておき、ウィンドウサイズの変更、クローズなどの処理を任せれば、継承を行うことなく、常に正方形を保つウィンドウの実現や、クローズ時の確認パネル表示が可能になります。

 なお、C#にデリゲートというメカニズムが備わっていますが、これは関数ポインタを抽象化したものと見なすことができ、メッセージの転送という意味合いは薄れています。

京都産業大学
京都産業大学コンピュータ理工学部教授。ソフトウエア開発手法、深層暗号などに関する研究を行う。オブジェクト指向とは20年以上の付き合いで、Mac OS X、iPhoneのアプリケーション開発も手がける。主な著書に「詳解 Objective-C 2.0」(ソフトバンク)。信州生まれだが関西暮らしが長い。http://www.kyoto-su.ac.jp/

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています