API设计的一些核心原则

没有经过设计的代码,是没有灵魂的。


鲁迅没说过这句话

设计涵盖的内容很广,而API设计是与日常开发关系比较紧密的一块。换句话说,掌握了一些核心的设计要领,对代码质量提升是立竿见影的。

无规矩不成方圆,API设计一样。最近学习了Google工程师总结的API设计原则,看完后,脑海中回忆起自己写的代码,方法的命名、参数顺序、异常处置、功能范围,无一不被作者所戳中。我觉得很有价值,所以拿来与大家一起分享,相信对你肯定有帮助。当然,作者总结的比较简洁,具体含义,需要大家思考并深入的体会,相信经过一番思考以后,定有收获。

由于原文是生肉,为了给部分小伙伴提供一些便利,我进行了翻译,翻译不好的地方还请指正,在此表示感谢。当然有喜欢生肉的同学,我也会在文末评论处贴上原文地址,请自取。

以下是正文部分。


image

API设计原则

通用原则

api应该只做一件事,并且要做好

  • 功能应易于解释
  • 如果很难对一个功能命名,通常是一个坏兆头
  • 好名称驱动开发
  • 模块能够拆分和合并

最小化内容访问权限

  • 类和成员变量尽可能私有化
  • 公共类不应该有公共变量(常量除外)
  • 最大化信息隐藏
  • 允许模块能够独立的使用、理解、构建、测试、调试

名字很重要 -api是一种小语言

  • 命名在很大程度上应该是不言自明的(避免过于隐晦的缩写)
  • 保持一致,同一个词应该始终代表一个含义(在整个api、跨平台的api)
  • 保持规律性-力求对称
  • 代码应该读起来像散文,如:
if (car.speed() > 2 * SPEED_LIMIT){
    generateAlert("Watch out for cops!);
}

文档很重要

重用是一种说起来容易做起来难的事情。要做到这一点,需要良好的设计和非常好的文档。即使当我们看到良好的设计(这仍然是不常见的)时,如果没有良好的文档,我们也不会看到组件被重用。
- D. L. Parnas, _Software Aging.
Proceedings
of 16th International Conference Software
Engineering, 1994

虔诚的写文档

  • 为类、接口、方法、参数、异常、构造器编写文档
    • 类:实例代表什么
    • 方法:方法与使用者之间的约定,如先决条件、后决条件、副作用
    • 参数:表示单位、表单、所有权

api设计决策要考虑性能影响

  • 不好的决策可能会限制性能,如:
    • 类型可变(参考下一条的例子)
    • 使用构造方法替换工厂
    • 使用实现类型代替接口
  • 不要试图通过包装api来提升性能
    • 好的设计通常伴随好的性能

api设计决策对性能的影响是真实并且持久的

  • Component.getSize() 返回 Dimension
  • Dimension是可变的
  • 每次调用getSize()将会分配一个Dimension
  • 导致数百万不必要的对象
  • 即使在1.2版本中增加新方案,老的代码依旧执行很慢

api必须与平台和平共存

  • 按规律办事
    • 遵守标准的命名约定
    • 避免废弃的参数类型和返回类型
  • 利用好api的特性
    • 泛型、枚举、默认参数、varargs
  • 了解并避免api的陷阱
    • Finalizers, public static final arrays

类设计

减少可变性

  • 类应该是不可变的,除非有更好的理由
    • 优点:简单、线程安全、可重用
    • 缺点:每个值都有单独的对象
  • 如果是可变的,保持状态空间尽可能小和良好的定义
    • 明确何时调用那个方法是合法的

Bad: Date, Calendar
Good: TimerTask

子类只出现在有意义的地方

  • 子类化意味着可替代性
    • 仅当is_a关系才出现子类
    • 否则,请使用组合
  • 公共类不应该仅仅为了容易实现而子类化其他公共类

Bad: Properties extends Hashtable, Stack extends Vector
Good: Set extends Collection

设计和文档用于继承,否则就禁止它

  • 继承违反了封装原则,子类对超类的实现细节敏感
  • 如果你允许子类化,文档留作自用
  • 保守策略:所有的具体类都final化

Bad: Many concrete classes in J2SE libraries
Good: AbstractSet, AbstractMap

方法设计

不要让使用者做任何模块可以做的事情

  • 减少对样板代码的需求
    • 通常通过剪切和粘贴来完成
    • 丑陋,烦人,容易出错
image.png
image.png

不要违反最小化原则

  • api的用户不应该对api的行为感到惊讶
  • 这值得付出很大的努力,甚至牺牲一些性能
public class Thread implements Runnable {
    // Tests whether current thread has been interrupted.
    // Clears the interrupted status of current thread.
    public static boolean interrupted();
    }
}

快速失败-当发生错误时,尽可能早的报错

  • 编译时最好- 静态类型、泛型
  • 运行时,首先调用发生错误的方法
    • 方法应该是原子失败的

使用适当的参数和返回类型

  • 在输入时,优先选择接口类型而不是类
    • _提供灵活性、性能
  • 使用最具体的输入参数类型
    • 将错误从运行时移动到编译时
  • 如果存在更好的类型,不要使用string
    • 字符串是笨重的,容易出错的,而且很慢
  • 不要使用浮点数来表示货币值
    • 二进制浮点导致不精确的结果!
  • 使用double(64位)而不是float(32位)
    • 精度损失是真实的,性能损失可以忽略不计

使用一致的参数排序

  • 尤其重要的是,如果参数类型相同
  • 如Collections中的方法,第一个参数一般都是被修改或被查询的。
image.png
image.png

image.png
image.png

避免长的参数列表

  • 三个或更少的参数是理想的
    • 更多的用户将不得不参考文档
  • 一长串类型相同的参数是有害的
    • _程序员误转了参数
    • 程序仍在编译、运行,但行为不正常!
  • 两种缩短参数列表的技术
    • 拆分方法
    • 创建助手类来保存参数

避免需要异常处理的返回值

  • 返回零长度数组或空集合,而不是null

Bad:


image.png
image.png

异常设计

支持unchecked异常

•checked-客户必须采取恢复措施
•unchecked–编程错误
•过度使用checked的异常会导致样板


image.png
image.png

在异常中包含失败捕获信息

  • 允许诊断和修复或恢复
  • 对于未检查的异常,消息就足够了
  • 对于已检查的异常,提供访问器
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容