Eclipse プラットフォーム
API 契約規則
バージョン 0.15 - 改訂 12:00 May 30, 2001
Eclipse プラットフォーム API (およびその他コンポーネント) のクライアントの契約規則を以下に示します。
API とは?
Eclipse プラットフォームは、クライアント (プラグインを作成する ISV) が使用する API エレメントを定義します。
また、これらのプラグインも、クライアントに対し API エレメントなどを定義することができます。
API エレメントは、パブリック・フェースです。つまり、それらの動作や使用目的に関する仕様を含んでいます。
API エレメントは、サポートの対象となります。Eclipse プラットフォーム・チームは、
指定の動作から逸脱しているようなインプリメンテーションのバグを修正します。
API の大幅な変更に伴うコストは高くつくことが多いため、
Eclipse プラットフォーム・チームは、メジャー・リリースを継続的に行い、API エレメントを引き続き発展させていく予定です。
API と非 API の区別
API エレメントは、その性質上、文書化されて仕様を持つものです。
一方、内部的なインプリメンテーションの詳細である非 API エレメントは、通常、
パブリッシュされたドキュメンテーションや仕様を持ちません。
したがって、対象についてのドキュメンテーションが見つからない場合、
これは、通常、API ではないものと見なすことができます。
より明確に区別をするならば、プラットフォームのコード・ベースは API と非 API パッケージに分離されており、
すべての API エレメントは、専用の API パッケージに宣言されています。
-
API パッケージ - 少なくとも 1 つの API クラスまたは API インターフェースを含む Java パッケージ。
API パッケージの名前は、そのコンポーネントのドキュメンテーション内に示されており、
インプリメンテーションの詳細のみを含むその他すべてのパッケージは、パッケージ名の適切な箇所に "internal" を含みます。
API パッケージの名前は、クライアント・コード内で使用することができます。
Eclipse プラットフォームの場合、次のものがあります。
-
org.eclipse.foo.* - 例、org.eclipse.swt.widgets、
org.eclipse.ui、または org.eclipse.core.runtime
-
org.eclipse.foo.internal.* - 非 API の内部インプリメンテーション・パッケージ
-
org.eclipse.foo.examples.* - 非 API の例
-
org.eclipse.foo.tests.* - 非 API のテスト・スイート
-
API クラスまたはインターフェース - API パッケージ内の public クラスまたはインターフェース、
あるいは他の API クラスまたはインターフェースに宣言、またはこれにより継承される、
public または protected クラスまたはインターフェースのメンバー。
API クラスおよびインターフェースの名前は、クライアント・コード内で使用することができます。
-
API メソッドまたはコンストラクター - API クラスまたはインターフェースに宣言、またはこれにより継承される、
public または protected メソッドまたはコンストラクター。
API メソッドの名前は、クライアント・コード内で使用することができます。
-
API フィールド - API クラスまたはインターフェースに宣言、またはこれにより継承される、
public または protected フィールド。
API フィールドの名前は、クライアント・コード内で使用することができます。
これら以外はすべて内部のインプリメンテーション詳細と見なされ、いずれのクライアントからも使用することはできません。
クライアント・コードが非 API エレメントの名前を参照することがあってはなりません (Java リフレクションを使用する場合でも)。
場合によっては、Java 言語の名前アクセス規則が、不当な参照を拒否するのに使用されます。
ただし、これが不可能である場合が多くあります。
この単純な規則を 1 つ守ることにより、問題を完全に回避することができます。
-
公式に文書化された API の順守。コンポーネントの パブリッシュ済み API Javadoc に文書化された
パッケージのみを参照してください。
名前に "internal" を含む他のコンポーネントに属すパッケージは参照しないでください。これは API ではありません。
パブリッシュされた API Javadoc が存在しないパッケージも参照しないでください。これも API ではありません。
一般規則
API エレメントの仕様は、エレメントの Java ソース・コード内の Javadoc コメントから生成されます。
一部のタイプのエレメントについては、仕様は契約の形式をとっています。
例えば、メソッドの場合、2 者 (メソッドの呼び出し元とメソッドのインプリメント担当) 間の契約となります。
基本的な規則は次のとおりです。
-
すべての契約の順守。契約は、使用する API エレメントのパブリッシュ済み Javadoc に記されています。
API 契約中で用いられている "must" は、条件を必ず満たすことの確認が義務とされることを意味します。
これを怠った場合、仕様外の (おそらくは予期しない) 結果をもたらすプログラミング・エラーと見なされます。
-
"must" の順守。"must" が含まれる条件については特に細心の注意を払ってください。
その他の一般的な規則
-
偶然の振る舞いに依存しない。偶然の振る舞いとは、実験的あるいは実際にみられる振る舞いであっても、
API 仕様によって保証されない振る舞いのことです。
-
NULL をオブジェクトとして扱わない。NULL の使用は、オブジェクトが存在しないことを示すものではありません。
API 仕様に記されていない限りは、すべて非 NULL であるとを想定してください。
-
Java リフレクションを誤って使用しない。Java リフレクションを使用して
Java コンパイラーの検査を妨げることは無意味です。
リフレクションの使用に関しては、追加の API 契約はありません。
リフレクションを使用することにより、
仕様外の振る舞いや内部のインプリメンテーション詳細への依存の可能性を高めることになります。
-
自らのパッケージを使用する。他のコンポーネントに属するパッケージのコードを宣言しないでください。
自らのパッケージには、必ず自らのコードを宣言してください。
public API メソッドの呼び出し
ほとんどのクライアントでは、クライアントが適切な呼び出しを行った場合は、
多くの Eclipse API は、API インターフェースまたはクラスにおける public メソッドの形をとります。
-
前提条件の確認。API メソッドの前提条件を満たすことを確認してから、メソッドを呼び出すようにしてください。
逆に言うと、呼び出し元は、呼び出しが戻されるのを受けてすぐメソッドの事後条件が確実に満たされることを想定できます。
-
NULL パラメーター。パラメーターに NULL の使用が可能であると文書に明示されていない限りは、
API メソッドに NULL をパラメーターとして渡さないでください。
これは、最も頻繁に起きるプログラミング・エラーです。
-
呼び出し元の制限。特定の呼び出し元に対してのみ使用可能と記されている API メソッドは、
その呼び出し元でない限りは呼び出さないでください。
場合によっては、呼び出し元の特定のクラスが使用できるように、
メソッドを public API の一部とする必要がありますが (internal であることが多い)、
これらのメソッドの呼び出しのタイミングを誤ると、仕様外の (おそらくは予期しない) 結果となります。
-
メソッドのデバッグ。"for debugging purposes only" とラベルの付いた API メソッドは呼び出さないでください。
例えば、toString() メソッドはほとんどがこのカテゴリーに該当します。
-
パラメーターの取得。配列、集合、またはパラメーターとして使用可能なその他のオブジェクトを API に渡して、
渡されたオブジェクトを変更することがないようにしてください。
これは問題の原因となるだけです。
プラットフォーム API クラスのインスタンス化
すべての具象 API クラスは、誰でもインスタンス化することができるわけではありません。
API クラスには、インスタンスの作成が許可される条件を記したインスタンス化の契約があります。
この契約は、その他初期化に関する責任 (例、インスタンスが完全にアクティブになる前の特定のプロパティーの構成など)、
および関連するライフ・サイクルに関する責任
(例、dispose() を呼び出し、インスタンスに依存する OS リソースを解放する) なども対象としています。
クライアントによってインスタンス化されるよう設計されているクラスは、
Javadoc のクラス・コメント中に、明示的にフラグが付けられています ("Clients may instantiate" など)。
-
インスタンス化の制限。特定の担当者に対してのみ使用可能と記されている API クラスは、
これに該当しない限りはインスタンス化しないでください。
場合によっては、特定の担当者が利用できるように、
クラスを public API の一部とする必要がありますが (internal であることが多い)、
これらクラスのインスタンス化のタイミングを誤ると、仕様外の (おそらくは予期しない) 結果となります。
プラットフォーム API クラスのサブクラス化
API クラスのサブセットのみ、サブクラス化されるよう設計されています。
API クラスには、サブクラス化の宣言が許可される条件を記したサブクラス化の契約があります。
この契約は、初期化やライフ・サイクルに関する責任についても対象としています。
クライアントによってサブクラス化されるよう設計されているクラスは、
Javadoc のクラス・コメント中に、明示的にフラグが付けられています ("Clients may subclass など)。.
-
サブクラス化の制限。サブクラス化するよう設計されていない API クラスはサブクラス化しないでください。
これらのクラスは、final と宣言された場合と同様に扱ってください。(これらは、"soft final" クラスと呼ばれる場合があります。)
protected API メソッドの呼び出し
通常、継承された protected および public メソッドをサブクラス内から呼び出すことができます。
ただし、階層の外部から public メソッドを呼び出す場合に比べて注意が必要です。
API メソッドのオーバーライド
public および protected API メソッドのサブセットのみ、オーバーライドされるよう設計されています。
各 API クラスには、サブクラスのオーバーライドが許可される条件を記したサブクラスの契約があります。
デフォルトでは、オーバーライドは許可されません。
実際のメソッドのインプリメンテーションをオーバーライドするには、そのサブクラスの契約を確認することが重要です。
メソッドをオーバーライドする際、サブクラス契約の内容は自動的には受け渡されません。
-
明示的な許可がない限りは public または protected API メソッドをオーバーライドしない。
特に指示がない限り、すべてのメソッドは final と宣言された場合と同様に扱ってください。
(これらは、"soft final" メソッドと呼ばれる場合があります。)
可能なオーバーライドのタイプは次のとおりです。
"implement" - サブクラスにおいて宣言された抽象メソッドは、
具象サブクラスによってインプリメントされなければなりません。
"extend" - サブクラスにおいて宣言されたメソッドは、スーパークラスのメソッドを呼び出す必要があります (一度のみ)。
"re-implement" - サブクラスにおいて宣言されたメソッドは、スーパークラスのメソッドを呼び出さないでください。
"override" - サブクラスにおいて宣言されたメソッドは、スーパークラスのメソッドを適宜呼び出すことができます。
-
事後条件の確認。API メソッドに指定された事後条件が、
戻りを受けてインプリメンテーションにより満たされていることを確認してください。
-
前提条件の確認。API メソッドに指定された前提条件が、入力時に必ず満たされているとは見なさないでください。
メソッドのインプリメンテーションは、その権限において指定の前提条件をチェックませんが、
誤った呼び出し元に対する警告となるよう、
(可能であり妥当なコストの範囲であれば) 前提条件をチェックすることが望ましいでしょう。
-
NULL 結果。(指定するインターフェースまたはスーパークラスにおいて) 結果が NULL を許可すると明示的に記されていない限り、
API メソッドの結果として NULL を戻さないでください。
-
コピーを戻す。API メソッドからの結果として、置換不能な配列、集合、
またはその他の変更が可能なオブジェクトを戻さないでください。
呼び出し元がオブジェクトを変更することのないよう、必ずコピーを戻すようにしてください。
プラットフォーム API インターフェースのインプリメント
API インターフェースのサブセットのみ、クライアントによりインプリメントされるよう設計されています。
API インターフェースには、インプリメントが許可される条件を記した契約があります。
クライアントによってインプリメントされるよう設計されているインターフェースは、
Javadoc のクラス・コメント中に、明示的にフラグが付けられています ("Clients may implement など)。
クライアントは、インプリメントを許可されている場合にのみ、
API インターフェースのサブインターフェースを宣言することができます。
-
インプリメントの制限。特定の担当者に対してのみ使用可能と記されている API インターフェースは、
これに該当しない限りはインプリメントしないでください。
多くの場合、インターフェースは、内部のインプリメンテーションの詳細をビューから隠すために使用されます。
public API メソッドのインプリメント
「API メソッドのオーバーライド」を参照。
API クラスおよびインターフェースのフィールドへのアクセス
クライアントは、API フィールドを読み取ることができ、そのほとんどは、final です。
構造体のようなオブジェクトには、非 final の public フィールドを持つものがあり、
特に指定がない場合、クライアントはその読み取りと書き込みが可能です。
-
NULL フィールド。明示的に許可されない限りは、API フィールドを NULL に設定しないでください。
既知の API タイプのオブジェクトのキャスト
既知の API タイプのオブジェクトは、API で明示的に許可されている場合、
異なる API タイプにのみキャスト (または instanceof を使用し条件付きでキャスト) することができます。
-
キャストおよび instanceof。instanceof を使用して式をキャストし、
API がサポートする内容以上にオブジェクトに関する情報を増やさないでください。
不適切に使用した場合、API により保証されない付随的なインプリメンテーションの詳細が公開される場合があります。
また、いずれのオブジェクトも非 API クラスまたはインターフェースにキャストすることは妥当ではありません。
規則に従わない場合
故意であるかどうかにかかわらず、規則に従わない場合には影響があります。
API 規則に従わない場合に警告を与えることができれば、関係者全員にとって事態は容易になります。
ただし、それはあり得ません。
多くの場合、API 適合が自主管理制度として機能し、
クライアントがそれぞれ規則を熟知しこれに従う責任を負います。
API エレメントにおける契約は、サポートされ認可された振る舞いの範囲を定めています。
Eclipse プラットフォームの機能の充実・改良が進むにあたり、その開発内容を示すことは API 契約の役割となります。
この契約の範囲外の内容は、いずれもサポートの対象外であり、
時期を定めず (リリース途中、または各種 OS プラットフォーム間でも) 通知なしに変更される場合があります。
上記規則に従わないクライアント・コードは、異なるバージョンやパッチ・レベルのプラットフォーム、異なる OS、
共存するプラグインの各種組み合わせ、または異なるワークベンチ・パースペクティブで実行した場合に失敗する可能性があります。
実際に、違反を犯した結果がどうなるかを試してみようとは誰も思わないでしょう。
規則を無視した場合に、警告がなかったと弁解することはできません。
「既に通知済み」のことです。
一方、規則に従ったクライアントのプラグイン・コードは、
バージョンやパッチ・レベルの異なるプラットフォーム、異なる OS での動作が可能であり、
他のプラグインとの共存も問題ありません。
関係者全員が規則を順守することにより、Eclipse プラットフォームは
新製品を開発するための安定したサポートを提供する基盤となります。