Eclipse 平台
API 实施规则
版本 0.15 — 上次修订时间:2001 年 5 月 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 包中的公共类或接口,或在其它某种
API 类或接口中声明的或由该类或接口继承的公共或受保护类或接口成员。API
类和接口的名称可合法地出现在客户机代码中。
-
API 方法或构造函数 — 在 API 类或接口中声明的或由该类或接口继承的公共或受保护方法或构造函数。API
方法的名称可合法地出现在客户机代码中。
-
API 字段 — 在 API 类或接口中声明的或由该类或接口继承的公共或受保护字段。API 字段的名称可合法地出现在客户机代码中。
将别的任何东西认为是内部实现详细信息且不受所有客户机限制。合法的客户机代码决不能引用非
API 元素的名称(甚至不能使用 Java 反映)。在某些情况下,Java
语言的名称可访问性规则用来禁止非法引用。但是,在许多情况下,这是不可能的。遵守以下简单规则就可完全避免这个问题:
-
只使用正式归档的 API。仅引用在组件的已发布的
API Javadoc 中归档的包。不要引用属于另一组件的名称中具有“internal”
的包 — 这些包绝对不是 API。不要引用没有任何已发布 API Javadoc 的包 — 这些包也不是 API。
一般规则
API 元素的规范是根据该元素的 Java 源代码中的 Javadoc 注释生成的。对于某些类型的元素,规范的格式为合同。例如,在方法的情况下,合同是以下两方间的合同:方法的调用者和方法的实现者。基本规则是:
-
尊重所有合同。在您正在使用的 API 元素的已发布 Javadoc 中描述了合同。
词语“必须”用于 API 合同中时,表示双方都有责任务必遵从所列条件;做不到这一点则被认为是一个会导致未指定(且可能是不可预测的)后果的编程错误。
-
必须尊重“必须”。要特别留意使用了“必须”的情况。
其它普通规则:
-
不要依赖偶然行为。偶然行为是由实验或在实践中观察到的行为,但任何
API 规范都不保证这些行为。
-
不要将 null 视作对象。相反,null 是缺少对象。除非 API 规范另有说明,否则将任何事项都假设为非 null。
-
不要试图用 Java 反映来进行欺骗。使用 Java 反映以防止 Java 编译器检查不会给你带来任何好处。对于反映的使用,不存在任何其它 API 合同;反映只是增加依赖未指定行为和内部实现详细信息的可能性。
-
使用您自己的包。不要在属于另一组件的包中声明代码。始终在您自己的包中声明您自己的代码。
调用公共 API 方法
对于大多数客户机,大多数 Eclipse API 在 API 接口或类上采取公共方法的形式,适当时供客户机调用。
-
确保先决条件。在调用 API 方法之前,一定要确保满足该方法的先决条件。相反,调用者可安全地假设方法的后续条件在从调用返回时已立即符合。
-
null 参数。不要将 null 作为参数传送给 API 方法,除非该参数被显式地说明为允许 null。这可能是最常发生的编程错误。
-
受限制的调用者。不要调用说明为仅可用于某些调用者的 API 方法,除非您是这些调用者之一。在某些情况下,为了某类调用者(通常是内部调用者)的利益,方法必须是公共 API 的一部分;在不适当的时候调用这些方法之一会发生未指定的(且可能是不可预测的)后果。
-
调试方法。不要调用标有“仅供调试”的 API 方法。例如,大多数 toString() 方法都属于此类别。
-
参数捕获。不要将任何数组、集合或其它易变的对象作为参数传送到
API 方法而后修改传送来的对象。这只会惹来麻烦。
实例化平台 API 类
并非所有具体 API 类都可被任何人实例化。API 类具有一个指示可据其创建实例的条款的实例化合同。合同可能还涉及如剩余的初始化责任(例如:在实例完全活动之前配置某个属性)和相关联的生命周期责任(例如:调用
dispose() 以释放实例占用的操作系统资源)之类的事项。在
Javadoc 类注释中对供客户机实例化的类显式地作了标志(标以类似于“客户机可实例化”之类的词).
-
受限制的实例化者。不要实例化说明为仅可用于某几方的 API
类,除非您是这几方之一。在某些情况下,为了某一方(通常是内部的)的利益,类必须是公共 API 的一部分;不正确地实例化这些类之一会发生未指定的(且可能是不可预测的)的后果。
子类化平台 API 类
仅可对 API 类的某个子集子类化。API 类具有一个指示可据其声明子类的条款的子类合同。此合同还涉及初始化责任和生命周期责任。在
Javadoc 类注释中对供客户机子类化的类显式地作了标志(标以类似于“客户机可子类化”之类的词).
-
受限制的子类化程序。不要子类化不供子类化的 API 类。将这些类视为它们已声明为终态。(这些类有时称为“软终态”类)。
调用受保护 API 方法
通常允许从子类中调用继承的受保护和公共方法;但是,与从层次结构外部调用公共方法相比,这通常需要更小心地来正确进行调用。
覆盖 API 方法
仅可覆盖公共和受保护 API 方法的某个子集。每个 API
方法都有一个指示一些条款的子类合同,子类可根据这些条款覆盖该方法。缺省情况下,是不允许进行覆盖的。对被覆盖的实际方法实现检查子类合同是很重要的;在覆盖该方法时,不会自动传送子类合同的条款。
-
不要覆盖公共或受保护 API 方法(除非显式允许这样做)。除非另有指示,否则将所有方法都视为它们已声明为终态。(这些方法有时称为“软终态”方法)。如果允许的覆盖种类为:
“实现”— 在子类上声明的抽象方法必须由具体的子类实现
“扩展”— 在子类上声明的方法必须调用超类上的方法(就调用一次)
“重新实现”— 在子类上声明的方法一定不能调用超类上的方法
“覆盖”— 在子类上声明的方法可自由调用超类上的方法(若前者认为合适的话)
-
确保后续条件。务必确保在返回时实现满足为
API 方法指定的任何后续条件。
-
事先检查先决条件。不要假设在进入时已必定满足为
API 方法指定的先决条件。虽然方法实现有权不检查指定的先决条件,但通常最好还是检查先决条件(在可行且不十分昂贵时)以使自己不要成为错误调用者。
-
null 结果。不要从 API 方法将 null 作为结果返回,除非已显式地说明了(在指定的接口或超类上)结果允许 null。
-
返回副本。不要从 API 方法将不可替换的数组、集合或其它易变对象作为
结果返回。始终返回副本就可以避免调用者可能修改对象引起的麻烦。
实现平台 API 接口
客户机仅可实现 API 接口的某个子集。API 接口具有一个指示根据其可实现这些接口的条款的合同。在
Javadoc 类注释中对供客户机实现的接口显式地作了标志(标以类似于“客户机可实现”之类的词). 客户机可声明 API 接口的子接口(当且仅当允许客户机实现子接口时)。
-
受限制的实现器。不要实现说明为仅可用于某几方的 API
接口,除非您是这几方之一。在许多情况下,接口用来将内部实现详细信息从视图中隐藏起来。
实现公共 API 方法
参见“覆盖 API 方法”。
访问 API 类和接口中的字段
客户机可读取 API 字段(它们大部分为终态)。某些结构类似的对象可能具有非终态的公共字段,除非另有指示,否则客户机可读写这些字段。
-
null 字段。不要将 API 字段设置为 null,除非显式允许这样做。
转换已知 API 类型的对象的类型
已知 API 类型的对象仅可转换为另一 API 类型(或有条件地使用 instanceof 进行类型转换),如果在 API 中显式允许这样做的话。
-
数据类型转换和 instanceof。不要使用
instanceof 和 cast 表达式来将有关某对象的已知内容增加到超过 API 支持的范围。不正确的使用会公开 API 不保证其正确性的偶然实现详细信息。
当然,将任何对象的类型转换为非 API 类或接口总是不合适的。
不遵循规则
不管是有意还是无意造成的,结果都有违规则。如果有因为您破坏了规则而惩罚您的 API 警察,则一切都会容易得多。但是,情况并非如此。对于大部分情况,API 一致性是作为一个荣誉系统运作的,每一个客户机都有责任了解规则并遵守它们。有关 API 元素的合同定界受支持的和持续的行为。随着
Eclipse 平台的成熟和发展,指导其如何发展的将会是 API 合同 。脱离了这些合同,任何事情都不受支持,可在任何时候(甚至在发布过程中或在不同的操作系统平台之间)不另行通知即进行更改。不符合上述规则的客户机代码在以下情况下可能会失效:在平台的不同版本和补丁级别上;在不同的底层操作系统上运行时;以另一共同驻留插件组合运行时或以另一工作台透视图运行时等等。实际上,甚至没有人会有兴趣去思考任何特定违规事件到底会怎样对您产生负面作用。对于那些忽略规则的人,不要说我们没有警告过您呵。要是发生了问题,最多会有人跟您说“我告诉过您的”。
另一方面,遵循上述规则的客户机插件代码应继续在平台的不同版本和补丁级别上工作、在不同的底层操作系统上工作并应与其它插件和平共处。如果每个人都按这些规则办事,则
Eclipse 平台将为构建令人兴奋的新产品提供稳定且受支持的基础。