Java API 设计清单
2022-08-12 17:33:40 22 举报
AI智能生成
Java API 设计清单
作者其他创作
大纲/内容
1. 包设计清单
1.1 共通
1.1.1 建议把 API 和 实现放入不同的包
1.1.2 建议把 API 放进上层包,而把实现层放进下层包
考虑把一组大型的API分拆进不同的包
考虑把 API 和实现打包进不同的 jar 包
避免 API 的实现类之间的内部依赖
避免把 API 分拆的太细
避免把公共实现类放到API的包中
不要在调用者和实现类之间建立依赖
不要把没有关系的API放进同一个包
不要把API和SPI(service provider interface)放进一个包
(注:两者不同可以查看这个页面http://stackoverflow.com/questions/2954372/difference-between-spi-and-api)
(注:两者不同可以查看这个页面http://stackoverflow.com/questions/2954372/difference-between-spi-and-api)
不要移动或者重命名一个已经发布的公共API
1.2 命名
一级包名以公司 或者组织的根命名空间来命名
使用一个稳定的产品名称或者一个产品系列的名称作为包的二级名称
使用 API 名成作为包名的(三级名称)结尾
考虑把仅包含实现的包的名称中包含 “internal”这个单词
(注:似乎 “impl”更常见一些)
(注:似乎 “impl”更常见一些)
避免使用组合起来的名称
避免包名和包内的类名使用同样的名称
避免在包名称中使用 “api”这个词
不要使用营销、计划、组织单元(部门)和地理名称
不要再包名中使用大写字母
1.3 文档
为每一个包提供一个package.html
遵循标准的 javadoc 的规范
在 API 的开始处用一句短小的话来概括(描述)
提供足够的细节来帮助判断是否需要使用和如何使用该 API
支持该 API 的入口(主要的类或者方法)
包含覆盖主要的,基本功能演示的样例代码
包含一个指向开发者指南的超链接
包含一个指向手册的超链接
指出相关到的 API集合
包含 API 的版本号
用 @deprecated 标记出不在使用的 API 版本
考虑添加一个版权声明
避免过长的包描述
不要在发布的 javadoc 中包含实现相关的包
2. 类型设计清单
(这里的“类型”个人理解为一组Api)
(这里的“类型”个人理解为一组Api)
2.1 共通
确保每种(设计的)类型都有单一明确的目的
确保每种类型代表了(业务)领域的概念,而不是为了技术上的抽象
限制类型的总数量
限制类型的大小
设计相关的类型时保持和原有的类型的一致性
建议为多种public的类型提供多种(private)的实现
建议接口的实现类和继承关系的类应该在行为上保持一致
建议用抽象类而不是接口解耦 Api 的实现
建议使用枚举而不是常量
考虑使用泛型
考虑在泛型上参数上增加约束
考虑使用接口来实现继承的效果
避免为使用者的扩展(需求)进行设计
避免深度的继承层级
不要使用 public 内嵌的类型
不要声明 public 和 protected 的变量
不要把实现的继承关系暴露给使用者
2.2 命名
使用名词或者名词词组
使用 PascalCasing
(驼峰命名法的别称详见
https://en.wikipedia.org/wiki/Camel_case)
(驼峰命名法的别称详见
https://en.wikipedia.org/wiki/Camel_case)
缩写仅第一个字母大写
为类型的实际作用使用精确的名称命名
为最常用的类型准备最短最容易记忆的名称
所有异常都以“Exception”结尾
使用名词的单数(比如Color而不用Colors)来命名枚举类型
考虑较长的名称
考虑派生类使用基类的名称结尾
考虑为抽象类名称使用“Abstract”开头
避免使用缩略语
避免太通用的名词
避免同义词
避免在相关的 Api 中使用类型的名称
不要使用仅大小写不同的名称
不要使用前缀
不要以“I”作为接口名称的开头
不要(重复)使用Java核心包中的名称
2.3 类
最小化实现使用的依赖
先列出public方法
声明实现方法为 private
为一个public抽象类定义至少一个public
为基本的使用情况提供足够的缺省实现
设计基本上不变的类
把无状态,访问器,扩展(mutator个人理解为多种参数形式的方法)方法集合到一起
把扩展方法的数量控制到最少
考虑设计一个默认的无参的构造方法
考虑重写equal,hashCode方法
考虑实现Comparable接口
考虑实现Serializable接口
考虑使类可以容器的扩展
考虑声明类为 final
考虑为类的实例化提供一个 public 的构造方法
考虑使用自定义的类型来增强类的不可变性
考虑设计不可变的类
避免静态类
避免使用 Cloneable
不要向静态类中添加实例 duixi
不要为使用者不应该扩展的public抽象类提供public的构造方法
不要滥用初始化
2.4 接口
为每一个public接口提供至少一个实现类
为每一个public接口设计至少一个消费者
不要对一个已经发布的public接口添加新的方法
不要使用标记接口
(标记接口详见https://en.wikipedia.org/wiki/Marker_interface_pattern)
(标记接口详见https://en.wikipedia.org/wiki/Marker_interface_pattern)
不要把public接口设计成常量的容器(这个是在很常见......)
2.5 枚举
考虑为枚举类型指定一个0值("NONE"或者"Unspecialized"等等)
避免只有一个值的枚举
不要使用枚举实现开放式的值集合
不要为将来可能增加的值设计枚举
不要为已经发布的版本增加新的枚举值
2.6 异常
确保自定义的异常可以被序列化
考虑为每种类型定义一个不同的异常
考虑为代码访问提供更多的异常信息
避免深层次的异常继承
不要从Exception 和 RuntimeException以外的类派生自定义异常
不要直接从 Throwable 派生异常
不要在异常信息内包含敏感信息
2.7 文档
为每种类型(的API)配上概述
遵循标准Javadoc的约定
每种类型开头以一句短小的话概述
为是否使用以及如何使用该类型提供足够的细节来帮助做决定
解释如何实例化一个类型
为一个类型的主要使用情景提供样例代码
包含指向到开发指南的链接
包含指向手册的链接
显示相关的类型
用 @deprecated 标签声明过时的类型
文档具有不可变性
避免冗长的类概括
不要为私有方法生成Javadoc
3. 方法设计清单
3.1 共通
确保每个方法实现一个目的
确保相关的方法都是一个粒度级别
确保没有混合调用方法的公共代码
使所有方法的调用具有原子性
设计 protected 方法时要像 public 方法一样慎重
限制扩展方法的数量
设计扩展方法需要具有较强的稳定性
建议为一系列重载的方法设计一个泛型的方法
考虑使用泛型方法
考虑设计方法对,即两个方法的作用是相反的
避免"helper"方法
避免长时间执行的方法
避免调用者在普通使用中需要手动写循环
避免可选的参数影响方法的行为
避免不可重复调用的方法
不要删除一个已经发布的方法
不要在没有提供替换方法前把一个已经发布的方法标记为过时
不要修改一个已经发布的方法的签名
不要修改一个已经发布的方法的可观测行为(也许指的是输出之类)
不要增加一个已经发布方法的调用条件
不要减少一个已经发布方法的调用结果
不要为已经发布的public接口新增方法
不要为已经发布的 Api 新增重载
3.2 命名
用给力的,有表达力的动词作为名词起始
使用驼峰命名法(好奇怪,前面写的是 PascalNaming)
为 JavaBean的私有属性预留 "get" "set" "is" 等访问方法
使用对调用者熟悉的词语
尽量使用英语口语
避免使用缩略语
避免使用一般的动词
避免同义词
不要使用黑话
不要依靠参数的名称和类型判断方法的意义
3.3 参数
为参数选择最合适的类型
在相关方法的调用中对参数为null值的处理保持一致性
在相关方法中参数的名称,类型和顺序需要保持一致
在参数列表中把输出的参数放到输入参数之后
为重载的方法省略常用的默认参数以提供一个较短的参数列表
在无关的类型中为相同语义的操作提供重载方法
建议使用接口而不是具体类作为参数
建议使用集合而不是数组作为参数和返回值
建议使用一般集合而不是原始(无类型)集合
建议使用枚举而不是 Boolean 或者 Integer 作为参数
建议把单个参数放到集合或者数组参数之前
建议把自定义类型的参数放到Java标准类型参数之前
建议把对象类型的参数方法值类型的参数之前
建议使用接口而不是具体类作为返回值
建议把空的集合而不是null作为返回值
建议把返回值设计成可以作为其他方法的合法输入参数
考虑为不可变参数设计一个副本
考虑在内部存储弱引用的对象
避免参数数量变更
避免参数长度太长(超过3个)
避免连续的同类型的参数
避免用作输出或者输入输出的参数
避免方法重载
避免参数类型暴露实现细节
避免boolean参数
避免返回 null
除了Java核心 Api,避免把类型作为不相关的Api的返回值
避免把可变的内部对象作为返回值来引用
不要把预先设置的常量作为整型值参数使用
不要为将来的(扩展设计)考虑预留参数
不要在重载方法中改变参数的名称顺序
3.4 异常处理
只有在异常情况下才抛出异常
只需要为可恢复的错误抛出已确认的异常
为了通知 Api 使用错误而抛出运行时异常
在适当的抽象层抛出异常
进行运行时预置条件的检查
为一个被不能为 null 的参数抛出空指针异常
为一个除为 null 以外异常值的参数排除非法参数异常
为一个错误上下文环境中的方法调用抛出非法状态异常
在错误信息中显示出参数的预置条件
确保失败的方法调用不会产生单向的后果
为回调方法中的禁止使用的 Api 提供运行时检查
建议优先使用 Java 标准异常
建议提供抛出异常的条件的查询方法
3.5 重写
使用 @Override 注解
维持或弱化预置条件
维持或者加强后置条件(不好翻译,大概 output+effect的意思)
维持或者加强不可变性
不要抛出新增的运行时异常
不要更改方法的类型(无状态,访问器或者扩展方法等)
3.6 构造方法
最小化构造方法中的工作
为所有的属性设置合理的默认值
仅把构造方法的参数作为一种设置参数的快捷方法
校验构造方法的参数
以参数相应的属性为其命名
当提供了多个构造方法时,遵循指南对其进行重载
建议使用构造方法而不是静态的工厂方法
考虑使用无参的构造方法
如果不是总需要新的实例,考虑使用静态的工厂方法
如果你需要在运行时决定一个合适的类型,考虑使用静态的工厂方法
如果你需要访问外部的资源,考虑使用静态的工厂方法
当面临非常多的参数的时候,考虑使用生成器(builder)
当需要回避直接实例化类的时候使用 考虑private 的构造函数
避免创建非必要的对象
避免 finalizer
不要从无参的构造方法中抛出异常
不要向一个已经发布的类中添加显式的构造方法
3.7 Setters 和 getters
以 get 开头命名一个返回值不为 boolean 的访问属性的方法
以 is,can 开头命名一个返回值为 boolean 的访问属性的方法
以 set 开头命名一个更新本地变量的方法
校验setter方法的参数
最小化getter和setter方法的工作
考虑从一个 getter 方法中返回不可变的集合
考虑实现一个 private 接口的集合替代 public 的集合属性
考虑只读的属性
设置可变类型的属性时考虑 Defensive Copy
(Defensive Copy 详见)
(Defensive Copy 详见)
当返回可变类型的属性时 考虑 Defensive Copy
getter 方法避免返回数组
避免根据方法内信息无法完成的校验
不要从 getter 方法中抛出异常
不要设计只能 set 的属性方法(仅有 public 的 setter 而没有 public 的 getter)
不要依赖属性设置的顺序
3.8 回调
设计时使用最严密的预置条件
设计时使用最弱的后置条件
考虑传递引用对象的方法中把回调接口作为第一个参数
避免有返回值的回调方法
3.9 文档
为每个方法提供 Javadoc 注释
遵循标准的 Javadoc 约定
每个方法以一句短小的话作为概述
声明相关的方法
用 @deprecated 标签声明过时的类型
显示所有过时方法的替换方法
避免冗长的 zhus
包含常用的使用模式
(如果允许的话)包含null值的确切含义
包含方法的类型(无状态,访问器或者扩展)
包含方法的预置条件
包含算法实现的性能特征
包含远程方法调用
包含访问外部资源的方法
包含哪些 API 可以在回调中使用
考虑为了描述方法的行为而包含单元测试
0 条评论
下一页