Eclipse 平台
API 使用規則
版本 0.15 - 上次修訂日期 2001 年 3 月 30 日 12:00
以下是用戶端使用 Eclipse 平台 API(及其他元件)的規則。
為什麼用 API
Eclipse 平台定義 API 元素供它的用戶端使用,也就是撰寫外掛程式的 ISV。
這些外掛程式又可以定義 API 元素,供它們的用戶端使用,依此類推。
API 元素是公開的介面:它們含有它們要做什麼及應該如何使用它們的相關規格。
API 元素在支援的範圍內:如果有不符合指定的行為,Eclipse 平台團隊會修正實作錯誤。
由於中斷 API 的變更相關成本非常高,因此,Eclipse 平台團隊也會嘗試在後續的主要版本中,適當地發展 API 元素。
如何區分 API 和非 API
在基礎本質,API 元素文件說明有其規格,而本身是內部實作細節的非 API 元素通常不會有公佈的文件或規格。
因此,如果您找不到某項目的文件,通常就代表它不是 API。
更明確地說,平台的程式碼基礎可區分成 API 和非 API 套件,所有 API 元素都宣告在指定的 API 套件中。
-
API 套件 - 至少含有一個 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 欄位 - public 或 protected 欄位,可宣告在 API 類別或介面中,或為 API 類別或介面所繼承。API 欄位的名稱可適當出現在用戶端程式碼中。
其他一切都視為內部實作細節,所有用戶端不在此限。
適當的用戶端程式碼絕對不能參照非 API 元素的名稱(甚至不能使用 Java Reflection)。
在某些情況下,會利用 Java 語言的名稱存取規則禁止不符合規定的參照。
不過,仍有些情況不可能採取這個方式。只要觀察一下這個簡單規則,就可以完全避免問題:
-
嚴格遵守文件說明的 API。請只參照元件的公佈 API Javadoc 中所說明的套件。請勿參照屬於名稱中有 "internal" 的另一元件之套件,這些絕非 API。 請勿參照沒有公佈 API Javadoc 的套件,這些也不是 API。
一般規則
API 元素的規格是從元素的 Java 原始碼中的 Javadoc 註解產生的。部份元素類型的規格採用合約的形式。
例如,在方法中,合約是在方法的呼叫者和實作者兩方之間。
基礎規則如下:
-
遵守所有合約。您使用的 API 元素的公佈 Javadoc 中有這些合約的說明。
當 API 文件使用「必須」一詞時,表示當事人必須確保永遠會符合條款;凡有不符,即視為程式錯誤,會帶來非指定(也可能是非預期)的結果。
-
您必須遵守「必須」。請特別注意使用「必須」一詞的條款。
其他常識規則:
-
不可根據雜項行為。雜項行為是試驗或操作時所觀察到的行為,但沒有任何 API 規格可提供其保證。
-
不可將空值當作物件來處理。空值比較像是沒有物件。除非 API 規格另有說明,否則,所有項目都是非空值。
-
不可嘗試使用 Java 反射。使用 Java 反射來規避 Java 編譯器檢查並沒有好處。反射的使用沒有其他 API 合約;反射只會增加依賴非指定行為和內部實作細節的可能性。
-
使用您自己的套件。請勿在屬於另一元件的套件中宣告程式碼。永遠要在您自己的套件中宣告自己的程式碼。
呼叫 public API 方法
對大部份用戶端而言,Eclipse API 的主體採 API 介面或類別中的 public 方法形式,讓用戶端在適當時可以呼叫它。
-
確定前置條件。在呼叫方法之前,請確定 API 方法的前置條件都符合。相反地,呼叫程式可能會安全地認為在從呼叫傳回之時,已即時完成了方法的前置條件。
-
空值參數。除非參數文件明確容許,否則,請勿將空值當作參數傳給 API 方法。這可能是最經常發生的程式設計錯誤。
-
限制呼叫者。請勿呼叫文件指出只適用於某些呼叫者的 API 方法,除非您就是所說明的呼叫者。 在部份情況下,為了得到某些呼叫者類別(通常是內部類別)的好處,方法必須是 public API 的一部份;在不當時機呼叫這些方法會發生非指定(也可能無法預期)的結果。
-
除錯方法。請勿呼叫有「除錯專用」標籤的 API 方法。例如,大部份 toString() 方法都是這類方法。
-
攫取參數。請勿將陣列、集成或其他容易改變的物件當作參數傳給 API 方法,再修改傳入的物件。這只會製造麻煩。
建立平台 API 類別的實例
不是任何人都可以建立所有具體 API 類別的實例。API 類別有一份建立實例的合約,指出建立實例所需遵循的條款。
合約也可涵蓋像剩餘起始設定責任(例如,在實例完全作用之前,配置某個內容)及相關生命週期
責任(如呼叫 dispose() 來釋出實例所緊握著的 OS 資源)等內容。
設計要由用戶端來建立實例的類別,在 Javadoc 類別註解中會有明確的旗標(含有類似「用戶端可以建立實例」的文字).
-
限制實例建立者。請勿建立文件指出只適用於某方的 API 類別之實例,除非您就是所說明的那一方。在部份情況下,為了得到某方(通常是內部)的好處,類別必須是 public API 的一部份;不正確地建立這些類別的實例會發生非指定(也可能無法預期)的結果。
建立平台 API 類別的子類別
只有 API 類別是設計成要建立子類別的。
API 類別有一份子類別合約,指出宣告子類別所需遵守的條款。
這個合約也涵蓋了起始設定和生命週期的責任。
設計要由用戶端來建立子類別的類別,在 Javadoc 類別註解中會有明確的旗標(含有類似「用戶端可以建立子類別」的文字).
-
限制子類別建立者。本來就不要建立子類別的 API 類別,請勿建立其子類別。請將這些類別當作已宣告為 final 來處理。 (這些有時也稱為「軟性最終(soft final)」類別)。
呼叫 protected API 方法
您通常可以從子類別中呼叫繼承的 protected 和 public 方法:不過,比起從階層外呼叫 public 方法,這種呼叫通常要更小心。
置換 API 方法
只有 public 和 protected API 方法的子集是設計成要加以置換的。
每個 API 方法都有一份子類別合約,指出子類別置換它時所要遵循的條款。預設值是不容許置換。
請務必檢查要置換的實際方法實作的子類別合約;當置換方法時,不會自動傳遞子類別合約的條款。
-
除非有明確許可,否則,請勿置換宣告為 public 或 protected 的 API 方法。
除非另有指示,否則,請將所有方法當作已宣告為 final 來處理。
(這些有時也稱為「軟性最終(soft final)」方法)。
如果容許置換的種類是:
實作 - 子類別宣告的抽象方法必須由具體的子類別實作
繼承 - 子類別宣告的方法必須呼叫超類別的方法(正好一次)
重新實作 - 子類別宣告的方法不能呼叫超類別的方法
置換 - 子類別宣告的方法可自由呼叫它認為適合的超類別方法
-
確定後置條件。請確定在傳回時,實作符合指定給 API 的任何後置條件。
-
主動檢查前置條件。請勿假設在輸入時,必然符合指定給 API 方法的前置條件。雖然方法實作有權不檢查指定的前置條件,但最好能檢查前置條件(如果可能且成本不同)使行為失當的呼叫者停下來。
-
空值結果。除非明確說明結果可為空值(在負責指定的介面或超類別中),否則,請勿以空值為 API 方法的傳回結果。
-
傳回副本。請勿傳回不可取代的陣列、集成或其他容易變化的物件作為 API 方法的結果。永遠要傳回副本,以避免可能修改物件的呼叫者帶來困難。
實作平台 API 介面
只有一部份 API 介面是設計成要由用戶端來實作的。
API 介面有一份合約指出實作它所需遵守的條款。
設計要由用戶端來實作的介面,在 Javadoc 類別註解中會有明確的旗標(含有類似「用戶端可以實作」的文字). 只有在 API 介面可以實作的情況下,用戶端才可以宣告 API 介面的子介面。
-
限制實作者。請勿實作文件指出只適用於某方的 API 介面,除非您就是所說明的那一方。在許多狀況下,介面都用來隱藏內部實作細節。
實作 public API 方法
請參閱「置換 API 方法」。
存取 API 類別和介面中的欄位
用戶端可以讀取 API 欄位,這些欄位大部份是 final 欄位。
某些類似結構的物件可能會有非 final public 欄位,除非另有說明,否則用戶端可以讀取和寫入它們。
-
空值欄位。除非明確許可,否則,請勿將 API 欄位設為空值。
強制轉型已知 API 類型的物件
如果 API 明確容許的話,已知 API 類型的物件只能強制轉型成不同的 API 類型(或利用 instanceof 進行有條件的強制轉型)。
-
cast 和 instanceof。請勿使用 instanceof 和 cast 表示式來增加超出 API 支援範圍的物件相關內容。 不當使用會外曝 API 所不保證的雜項實作細節。
當然,將任何物件強制轉型成非 API 類別或介面永遠是不恰當的。
違反規則
不論是有意或無意,違反規則都有其結果。
如果有 API 政策能制止規則的違反,事情會比較簡單。
不過,情況並非如此。
大體上,API 標準是受尊重的系統運作,每個用戶端都承擔瞭解和遵守規則的責任。
API 元素的合約界定支援而持續的行為。隨著 Eclipse 平台的發展和成長,將會由 API 合約來引導發展的呈現方式。在這些合約之外,一切都不在支援範圍內,隨時可能改變,且沒有通知(甚至中間版本或不同 OS 平台之間也是如此)。
凡是逾越這些規則的用戶端程式碼,當在平台的不同版本和 patch 層次上、在執行於不同的基礎 OS 時,在混合執行不同的共存外掛程式時,以及搭配執行不同工作台視景時,都可能失敗。
當然,沒人有意推斷任何特定的違規會如何回過頭來造成傷害。但選擇漠視規則的人,不能說沒有人提出警告,且最多只會得到早已告知的結果。
另一方面,遵守上述規則的用戶端外掛程式應該能歷經平台不同版本和 patch 層次、跨越不同的基礎 OS 而繼續運作,且應該能順利與其他外掛程式共存。
如果每一個都依規則而運作,Eclipse 平台會提供穩定的支援基礎,可供您在上面建置任何傑出的新產品。