65.9K
CodeProject 正在变化。 阅读更多。
Home

API设计快速概览

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (11投票s)

2009 年 4 月 29 日

CPOL

5分钟阅读

viewsIcon

29659

改进 API 设计方法的建议。

引言

无论你是否意识到,你都是一个 API(应用程序编程接口)的设计者。每次创建新类或增强现有类时,非私有的方法和属性都会创建或添加到 API 中。所以,我认为讨论如何创建良好的 API 是有意义的。

不幸的是,单篇文章的空间不足以涵盖良好 API 设计的所有主题。因此,我将简要介绍其中三个主题,为你提供一些其他资源,并请你贡献你对该主题的想法和问题。

让你的 API 易于正确使用

一个好的 API 应该易于正确使用。这意味着,它应该容易做正确的事,并且难以,如果不是不可能,错误地使用它。

我认为这一点很难反驳,但“易于正确使用”到底意味着什么?例如,让我们比较一下使用 Java SDK 中的 Date 类和 Joda Time 库中的 DateTime 类来确定给定日期是否是情人节的难易程度。

这是使用 java.util.Date 类的第一个尝试

public boolean isValentinesDay(java.util.Date date) {
    return((date.getMonth() == 2) && (date.getDay() == 14));
}

这看起来相当简洁,而且编码并不困难。不幸的是,它是错误的。让我们忽略第一个预期使用的方法已经被弃用多年并且不应再使用的事实,因为存在更隐蔽的问题。使用 getMonth() 的测试是错误的,因为 Date 使用零基计数来表示月份,所以我们需要将 getMonth() 的结果与 1 进行比较来测试二月。另一个问题是 getDay() 返回的不是月份中的某一天,而是星期几,其中星期日='0',星期六='6'。检索月份中某一天应调用的正确方法是 getDate(),尽管在我看来,在 Date 对象上调用 getDate() 应该返回它本身。

现在,让我们看看使用 Joda Time 库是什么样子

public boolean isValentinesDay(org.joda.time.DateTime date) {
    return((date.getMonthOfYear() == 2) && (date.getDayOfMonth() == 14));
}

这段代码也看起来简洁易用。它比 java.util.Date 示例需要多输入一点,但这有一个好处,就是它是正确的。在 Joda Time 中,月份是从 1 到 12,但如果你想让月份测试更清晰,可以使用 DateTimeConstants.FEBRUARY 而不是魔术数字 2。

在这个例子中,我认为 Joda Time 在让 API 易于正确使用方面做得比 Java SDK 好得多。

让你的 API 难以错误使用

防止人们对 API 做错事的意味着什么?这取决于 API 的预期用途。

对于 Date 类,它可能意味着不允许用户创建无效日期。因此,当用户尝试将月份设置为无效值(如 2009 年 2 月 30 日)时,你有一个选择:可以抛出异常,或者像 java.util.Date 类那样,将日期滚动到 3 月 2 日。

虽然这两种解决方案都可以防止用户设置无效日期,但默默地修复问题可能会很危险,因为用户可能没有意识到他们正在做任何错误的事情。抛出已检查异常有时被视为“不友好”,但它是明确告诉用户有问题的一种方式,这样他们就有机会在继续之前纠正问题。

以用户为中心设计你的 API

确定你的 API 应提供哪些方法和属性的最佳方法之一是编写一些代码来测试该 API。注意:你*不*必编写单元测试,尽管这样做是设计 API 和证明其有效性的绝佳方法。

作为为什么这一点很重要的例子,让我告诉你我最近看到的一些遗留代码。该 API 包括一个名为 getQueueCount() 的方法,该方法接受一个包含 JMS 队列名称的字符串,并返回该队列中可用消息的数量。该方法内部的大部分代码用于执行 JNDI 查找并获取命名队列的实例,而只有几行用于获取并返回消息计数。

这很糟糕的原因在于,在每次调用 getQueueCount() 的地方,调用类已经拥有了队列的引用,并且必须调用 getQueueName() 方法才能获取 getQueueCount() 方法所需的字符串。

如果 API 设计者编写了一些客户端代码,他们可能会注意到这种模式,并可以将 getQueueCount() 方法重构为接受对队列的引用。这将使客户端(无需调用 getQueueName())和编写 getQueueCount() 方法的开发人员更容易,因为他们不需要查找队列并检索其实例;他们只需获取消息计数并返回即可。

书籍、文章等

  • 《实用 API 设计》(Practical API Design),作者 Jaroslav Tulach - 这是一本由 NetBeans IDE 的创始架构师编写的优秀 API 设计书籍。
  • 《人机界面》(Humane Interface), Martin Fowler 的 bliki(部分博客,部分维基)位于 https://martinfowler.com.cn/bliki/HumaneInterface.html - 包括指向其他有趣设计文章的链接。
  • 《如何设计一个好的 API 以及为什么它很重要》(How to Design a Good API and Why it Matters),作者 Joshua Bloch。这是 Josh 在 JavaPolis 2006 上发表的演讲视频链接:http://www.infoq.com/presentations/effective-api-design

现在,轮到你了

你是否有关于 API 设计的提示、技巧、建议、问题或警告?如果有,请将其添加到评论中,以便我们都能受益。

历史

  • 2009 年 4 月 29 日:文章提交。
© . All rights reserved.