现在的位置: 首页 > 综合 > 正文

人本接口

2013年08月15日 ⁄ 综合 ⁄ 共 2754字 ⁄ 字号 评论关闭

原文:HumaneInterface    设计        2005年12月5日            Bliki 索引

(更新频繁,见文尾增添的链接。)

在Ruby用户群中混迹了一段时日,我经常见到“人本接口”这个术语。“人本接口”体现了Ruby大虾们设计class接口时的态度,此外,我觉得它还与另一个学派(最小接口)在设计API的思路上形成了有趣的对照。

人本接口的本质思想是找出人们想要的操作并设计出接口,之后所有常见的操作都可以轻松搞定了。

与最小接口形成鲜明对比的是,人本接口容易变得非常肥大,其设计者对此也着实不怎么介意。这里的“肥大”不是说在实现的代码量上人本接口的class就一定比最小接口的大。两者的基本功能也往往非常相似。

拿Java和Ruby的链表组件做个对比,是观察人本接口与最小接口差异的一个好办法。Java提供了一个interface(java.util.List),它声明了25个实例方法,而Ruby的Array class(不是数组,而是个链表)有78个方法。数量的差异多少暗示出风格的不同(尽管还有许多其他原因可以解释这种差异)。两种组件提供的基本服务是相同的,不过Ruby的Array还包括了不少附加功能,但都是些小功能,用Java的最小接口也能实现。

举个小例子来展示一下它们的区别吧:得到一个链表末尾的元素。用Java你会这么写:

aList.get(aList.size -1)

用Ruby则为:

anArray.last

其实更让人奇怪的是,Ruby Array还有一个first方法,所以你不必写anArray[0],只需anArray.first。

还有一些复杂功能,比如Ruby Array的flatten方法,它能把嵌套的链表变成单独的一条:

irb> [1,2,[3,4,[5,6],7],8].flatten ⇒ [1, 2, 3, 4, 5, 6, 7, 8]

这里的要点是:不论简单如last还是复杂若flatten,所有这些功能都可以留给用户自己编写,而无需增加链表class的代码量。最小主义者倾向于聚焦一组必要方法的最小集合,来支持所有这些操作,人本主义者则尽量添加人们需要的方法。通常这些额外的方法被称作“便利方法(convenience methods)”——这个术语在最小主义者眼里并非“不可或缺品”之意。

这就引出一个问题:以什么标准来判断一个方法该不该添到一个人本接口里呢?要是把所有人可能用得到的所有方法全都添上,最后会造出一个极其复杂的class。人本接口设计者的处理原则是努力甄别哪些方法是一个class最常用的,再加以设计以方便大家使用。

这条原则不仅能帮你决定哪些方法要添加,还影响着怎样给它们取名字。在RubyConf上, Tanaka Akira指出常用方法优先取短名字的好处。那些方法用得多,因此我们很熟悉,短名字记起来也容易,另一个好处是名字短打字少读起来方便。例如class DateTime的parse方法,负责解析常用的日期格式,还有一个更灵活的方法叫strptime,能解析所有日期格式,但用得就没那么多了。

这条关于命名的原则与最小接口方案并不冲突。一个例证就是Java的List interface一登场就把老旧的Vector的elementAt方法改成了get。

方法别名是Ruby的人本接口哲学引发的另一个有趣现象。要想得到一个链表的长度,用length还是用size?有的库用length有的库用 size,而Ruby的Array两个都有,它们互为别名,调用哪个都是同一份代码。Ruby大虾们的观点是:与其让用户记住哪个库里有哪个名字不如两个都提供。

关于人本接口和最小接口的设计风格孰优孰劣的讨论太多了,长篇累牍惹人烦,所以在这儿我尽量总结一下人本接口支持者们的主要观点(反方观点见最小接口):

一个object的功能强弱主要不是取决于它有什么数据,而在于它有哪些操作。如果总是想着保持接口尽量窄小,哪怕是一些很常用的功能,也迫使用户们不得不一遍一遍地重复编码。比如上面提到的flatten操作,一些人会用递归实现,虽然不算难,但既然这个操作不是那么不常用,何必劳驾用户们呢?

即便是简单情况,比如取链表末尾元素,若没有last方法,还得让用户学会一个惯用法才能取到。一个简单方法就直接读取了,何必给用户加一层间接呢?优秀软件处处先为用户着想,为用户提供方便,人本接口就遵循用户为先原则。

人本接口做的越多,用户就越不需要亲自动手。尤其是用户们可借助这些API来简化日常任务——代码写起来、读起来都方便。

正反双方都不乏闪亮论点。就我个人而言,我倾向于人本接口一方,尽管我觉得它的难度确实更高。

后续讨论

经我这篇小文一煽动,引发了一些有趣而且有意义的讨论。等到了一定程度,我会在下面的链接旁加些叙述以方便大家阅读,但在那之前,我就先只把它们列出来吧。这场辩论主要是由Elliotte Harold对人本方式简短却鞭辟入里的批评以及James Robertson的回应(别忘了看Robertson帖子后面的评论)引发的。随后论战大潮就涌来了:| Cees de Groot | Antonio Vieiro | David Hoefler | James Higgs | Peter Williams | Cedric Beust | John D. Mitchell | Stuart Roebuck | Elliotte Harold (2) | Jon Tirsen | Hitesh Jasani | Blaine Buxton | Ramnivas Laddad | Anders Noras | James Robertson (2) | Kieth Ray | James Robertson (3) | Elliotte Harold (3) | Charles Miller | Rob Lally | Bernard Notarianni | David Crow | Jim Weirich | Jim Weirich (2) | Ian Bicking | Brian Foote | Justin Gehtland | Tom Moertel | Antonio Vieiro (2) | Kris Wehner | The Server Side | Ravi Mohan | Danny Lagrouw | Piers Cawley | Peter Williams | Florian Frank | Chris Siebenmann

除了上边的还有很多,我没搜罗齐全,列出这些的目的是希望让辩论多些有意思的东西,并避免恶言相向。Ruby Array VS Java List的例子过分吸引了大家的眼球,让人们忽视了其背后的道理,产生这种倾向是自然而然的。这场讨论已经发散出一些不错的方向,有机会的话我会试着说说其中一两个话题。

读一下Joey deVilla的文章也是个不错的选择,它包括了上边大部分链接的文摘。

抱歉!评论已关闭.