Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
2007-12-02 - トーフサロン
[go: Go Back, main page]

トーフサロン

Common Lisp クックブックもぼちぼちやってます。

2007-12-02

[][] Objective-CプロトコルJavaインターフェースの機能の比較  Objective-CのプロトコルとJavaのインターフェースの機能の比較 - トーフサロン を含むブックマーク はてなブックマーク -  Objective-CのプロトコルとJavaのインターフェースの機能の比較 - トーフサロン

某所の諸々の丁々発止の様を (・∀・) もしくは (0゚・∀・) しながら見ている方の中には、Objective-Cプロトコルに興味を持った方もいると思う。さればObjCのプロトコルJavaインターフェースの機能を比較してみるのも一興かと存じ、不肖僭越ながら此処にしたためる所存に候。

※ここで比較するのはあくまで言語仕様です。以下「インターフェース」は「JavaInterface」、「プロトコル」は「ObjCのProtocol」を指します。

定義できる要素

インターフェース
定数、メソッド、ネストしたクラスインターフェース
プロトコル
メソッド

インターフェースクラス-2(インスタンスを生成できない、メソッドを実装できない)の機能を持つ。インターフェースと強く関連するクラスインターフェースを、ネストすることで定義できる。

一方プロトコルはメソッドしか定義できない。Javaと異なり、ObjCのクラスプロトコルは専用の変数・定数を持てない。もしプロトコルに定数を含めたい場合、その定数を返すようなクラスメソッドを宣言する。

プロトコルと強く関連するクラスプロトコルを定義したい場合、特に方法はない。コメントドキュメントにでも書いておくしかない。

拡張継承

インターフェースプロトコル共に、複数のインターフェースプロトコル継承できる。

定義

比較メソッドを宣言したインターフェースプロトコルの例。どちらも宣言のみで、実装はできない。名前が異なる理由は後述。

Java:

public interface Comparable {
  int compareTo(Object o);
}

ObjC:

@protocol ComparisonMethods
- (int)compareTo:(id)anObject;
@end

メソッドの実装

それぞれ複数のインターフェースプロトコルを指定できる。

Java:

public class Body implements Comparable {
    int compareTo(Object o) {
       return ...;
    }
}

ObjC:

@interface Body <ComparisonMethods>
- (int)compareTo:(id)anObject;
@end
 
@implementation Body
- (int)compareTo:(id)anObject
{
	return ...;
}
@end

型指定

Java:

Comparable var;

ObjC:

id <ComparisonMethods> var;

インターフェースクラスと同じように型として指定できる。

ObjCではプロトコルクラスは別のもので、プロトコルを型としては指定できない。その代わりにプロトコルを指定する文法が用意されているので、id 型(オブジェクト型。JavaObjectに相当)とプロトコルを指定する。上の例では ComparisonMethods プロトコルを実装したオブジェクトを宣言することになる。もっともObjCではクラスプロトコルを指定する意味はあってないようなもので、間違ったら警告が出てラッキー、程度のもの。上の例のオブジェクトが本当にComparisonMethodsプロトコルに準拠しているかどうかはまったく保証されない。

宣言したメソッドをすべて定義せずにコンパイルした場合

インターフェース
エラー
プロトコル
警告。ただしコンパイラオプション -Wno-protocol か、もしくはXcodeアクティブターゲットの「Objective-C未実装のプロトコル」をチェックすることでエラーにできる。

インフォーマル(非公式)プロトコル

仕様ではないが、ObjCにはインフォーマルプロトコルというプロトコルの使い方がある。プロトコルは定義しておくが、どのクラスもそのプロトコルを適用しない。ただし、その中から必要なメソッドのみを実装する。コード上ではメソッドとプロトコルに何の関係もないのが特徴。

インフォーマルプロトコルは委譲でよく使われる。

例えばWebObjectsデータベースと通信するEOAdaptorChannelにはEOAdaptorChannel Delegateというインフォーマルプロトコルが用意されていて、EOAdaptorChannelから呼ばれるメソッドがたくさん宣言されている。もしEOFが発行するSQL文をチェックしたければ、デリゲートクラスadaptorChannelShouldEvaluateExpression だけ実装しておけばいい。インフォーマルプロトコルのメソッドは、無視しても問題ないようになっている(呼び出し側のオブジェクトがメソッドの有無をチェックしている)。

名前

インターフェース
語尾はableで終わることが多い
プロトコル
語尾がingで終わるか、名詞

上の例なら、比較メソッドを宣言したインターフェースはComparable、プロトコルはComparisonMethodsとなる。

まとめ、というか個人的な所感

インターフェースプロトコルは、案外似てるようで使い勝手が異なる。インターフェースクラスの性質に、プロトコルは振る舞いに注目しているらしい。

こうしてまとめてみると、おそらくインターフェースプロトコルの根っこは同じなんだと思う*2Javaオブジェクトクラスで縛ろうとする世界で、ObjCはメッセージで縛ろうとする世界だけど、どちらも単一継承世界でもある。その世界で多重継承のいいとこどりをしようとした結果、クラス中心に考えるJava世界に合うのがインターフェース、メソッド中心に考えるObjCの世界に合うのがプロトコルだったんじゃなかろうか。ObjCもSmalltalkと同じく、メッセージを送る相手のクラスをたいして気にしない。それよりも相手がどんなメソッドを持っているかが重要だから、メソッドの集合がクラスよりも重要な型になる。クラスだけが型じゃないよ。*3 *4

*1型じゃないから、「(型としての)Interfaceを実現していた」に対する答えはNO

*2ソースがないから憶測だよ

*3:自分でも勘違いして堂々と書いたけどw

*4:「(型としての)Interfaceを実現していた」の型がクラスのみを指すのでなければ、対する答えはYESになるね

sumimsumim 2007/12/03 10:28 「プロトコルは型ではない」というのがちょっとよく分かりませんでした。たとえば、プロトコルは(Obj-C 独特の弱いものながらも)型チェックの対象になるようですし、“Only instances can be statically typed to a protocol, just as only instances can be statically typed to a class. ”のようなクラスと対比した言い回しも許容されるように見受けられます。

sumimsumim 2007/12/03 10:35 あ、分かりました。よく読んでいませんでした(^_^;)。「プロトコルを型としては指定できない。」というあたりですね。

carvercarver 2007/12/03 13:15 あああ、ご指摘ありがとうございます。その文章修正して考え直したら結論が真逆になりましたw