跳转到内容

ROSE 编译器框架/良好 API 设计

来自维基教科书,开放世界中的开放书籍

Google: Joshua Bloch 著的“如何设计一个好的 API 以及它为什么重要”

待办事项:从 Markdown 转换

良好 API 的特点

[编辑 | 编辑源代码]
  • 易于学习
  • 易于使用,即使没有文档
  • 难以误用
  • 易于阅读和维护使用它的代码
  • 足够强大以满足需求
  • 易于扩展
  • 适合受众

API 设计流程

[编辑 | 编辑源代码]

[T]重复一个非常短的开发周期:首先,开发人员编写一个失败的自动化测试用例,定义所需改进或新功能,然后生成通过该测试的代码,最后将新代码重构到可接受的标准。

    • 同时作为示例/教程和单元测试
  • 保持现实的期望
    • 你不能取悦所有人……目标是让每个人都同样不满意
    • 预计 API 会发展;会犯错误;需要真实世界的使用

一般原则

[编辑 | 编辑源代码]
  > [A] measurement of actual performance [power / weight]
  • 不要给用户一把枪让他们自伤
    • 信息隐藏:最大程度地减少所有内容的可访问性

文档很重要

[编辑 | 编辑源代码]
  • 类:实例代表什么
* Method: contract between method and calling client (preconditions, postconditions, and side-effects)
* Parameter: indicate units, form, ownership

先决条件和后置条件

  • 先决条件语句表示在调用函数之前必须为真。
  • 后置条件语句表示在函数完成工作时将为真。
  /// \post <return_value>.empty() == false
  

API 与实现

[编辑 | 编辑源代码]

实现细节不应影响 API。不要让实现细节“泄漏”到 API 中。

性能

  • 为可用性设计,为性能重构
  • 不要为了提高性能而扭曲 API
  • API 设计决策对性能的影响是真实且永久的
    • Component.getSize()返回值Dimension
    • Dimension是可变的
    • 每次getSize调用都必须分配Dimension
    • 导致数百万次不必要的对象分配
  • API 必须与平台和平共处
    • 做习惯的事(标准)
    • 避免过时的参数和返回值类型
    • 模仿核心 API 和语言中的模式
    • 利用 API 友好功能:泛型、可变参数、枚举、默认参数
  • 不要让客户端做模块可以做的事情
    • 减少对样板代码的需求
  • 不要违反[最小惊讶原则](http://en.wikipedia.org/wiki/Principle_of_least_astonishment)
  > The design should match the user's experience, expectations, and mental models...aims to exploit users' pre-existing knowledge as a way to minimize the learning curve
  • 提供对所有以字符串形式提供的数据的编程访问权限 => 无需客户端字符串解析
  • 小心重载:模糊重载

名称很重要

[编辑 | 编辑源代码]
  • 基本上不言自明(避免使用神秘缩写)
  • 保持一致(例如,相同的词语意味着相同的事情)
  • 努力追求对称
  • 应该像[散文](http://en.wikipedia.org/wiki/Prose)一样阅读
 > [T]he most typical form of language, applying ordinary grammatical structure and natural flow of speech rather than rhythmic structure (as in traditional poetry).
      if (car.speed() > 2 * SPEED_LIMIT)
        generateAlert("Watch out for cops!");
    

输入参数

[编辑 | 编辑源代码]
  • 接口类型优于类:灵活性、性能
  • 最具体的类型:将错误从运行时移动到编译时
  • 使用double(64 位)而不是float(32 位):精度损失是真实的,性能损失可以忽略不计
  • 一致的排序:
      #include <string.h>
      char *strcpy (char *dest, char *src);
      void bcopy   (void *src,  void *dst, int n); // bad!
    
  • 简短的参数列表:3 个或更少;更多的话,用户就必须参考文档;类型相同的参数有害
    • 缩短参数列表的两种技巧:1)分解方法,2)创建辅助类来保存参数

返回值

[编辑 | 编辑源代码]
  • 避免需要特殊处理的值
 > For example, return a `zero-length array` or `empty collection`, not `null`
  • 不要强迫客户端使用异常进行控制流
  • 不要静默失败
  • 更喜欢未经检查的异常
  • 包含故障捕获诊断信息
  • 快速失败:尽快报告错误
    • 编译时:静态类型、泛型
    • 运行时:在第一个错误方法调用时出错(应该是故障原子
华夏公益教科书