background image

Java 程序】API 设计新思维:用流畅接口构造内部

DSL

  程序设计语言的抽象机制包含了两个最基本的方面:一是语言关注的基本元素/语义;
另一个是从基本元素/语义到复合元素/语义的构造规则。在 C、C++、Java、C#、Python 等
通用语言中,语言的基本元素/语义往往离问题域较远,通过 API 库的形式进行层层抽象
是降低问题难度最常用的方法。比如,在 C 语言中最常见的方式是提供函数库来封装复杂
逻辑,方便外部调用。
  不过普通的 API 设计方法存在一种天然的陷阱,那就是不管怎样封装,大过程虽然
比小过程抽象层次更高,但本质上还是过程,受到过程语义的制约。也就是说,通过基本
元素/语义构造更高级抽象元素/语义的时候,语言的构造规则很大程度上限制了抽象的
维 度 , 我 们 很 难 跳 出 这 个 维 度 去 , 甚 至 可 能 根 本 意 识 不 到 这 个 限 制 。 而
SQL、HTML、CSS、make 等 DSL(领域特定语言)的抽象维度是为特定领域量身定做的,
从这些抽象角度看问题往往最为简单,所以 DSL 在解决其特定领域的问题时比通用程序
设计语言更加方便。通常,SQL 等非通用语言被称为外部 DSL(External DSL);在通用语
言中,我们其实也可以在一定程度上突破语言构造规则的抽象维度限制,定义内部
DSL(Internal DSL)。
    本 文 将 介 绍 一 种 被 称 为 流 畅 接 口 (Fluent Interface) 的 内 部 DSL 设 计 方 法 。
Wikipedia 上 Fluent Interface 的定义是:
  A fluent interface (as first coined by Eric Evans and Martin Fowler) is an 
implementation   of   an   object   oriented   API   that   aims   to   provide   for   more 
readable code. A fluent interface is normally implemented by using method 
chaining to relay the instruction context of a subsequent call (but a fluent 
interface entails more than just method chaining).
  下面将分 4 个部分来逐步说明流畅接口在构造内部 DSL 中的典型应用。
  1. 基本语义抽象
  如果要输出 0..4 这 5 个数,我们一般会首先想到类似这样的代码:
  //Java
for (int i = 0; i < 5; ++i) {

  system.out.println(i);

  }

  而 Ruby 虽然也支持类似的 for 循环,但最简单的是下面这样的实现: