• 隐藏侧边栏
  • 展开分类目录
  • 关注微信公众号
  • 我的GitHub
  • QQ:1753970025
Chen Jiehua

Functional options for friendly APIs 

函数式选项模式对于设计友好的API有着重要的作用,它将会影响到你的API后期的扩展以及往前的兼容问题。

一个例子

假如我们要写一个简单的server,我们可以直接这么定义:

我们直接用将 addr 作为参数初始化 Server,很简单的实现,同时也很容易使用。

增加功能

随着我们第一个版本发布,可能会开始涌入新的需求:

  • 支持TLS?
  • 限制最大连接数?
  • 请求超时?
  • ……

于是,我们需要修改API加上这些新的需求:

然而,问题便来了:

  • 老用户需要修改代码才能适配我们新的接口;
  • 新用户容易对接口的参数感到迷茫,哪些使必须的,哪些使可选的;
  • 我可能只想开一个简单的server,与我无关的参数太多了;
  • ……

于是,我们可能会换一种方式来定义我们的API:

然而,随着参数增多,我们需要定义的API会逐渐变多,而且不一定保证满足用户需求。

Config Struct

所以我们改用另一种方式来初始化Server,定义一个 Config 结构:

这么做有一些好处:

  • 新的参数选项可以很容易地增加,而API可以保持不变;
  • 这种方式也可以更好地进行文档化(不需要为每个API都写文档,只在Config中说明即可);

不过,这种模式仍然不是最佳的,很多时候,用户使用API都希望默认行为就能很好的运行。

而Config这种模式反而潜在着让用户使用零值的问题(Go中未赋值,则默认使零值),并可能会导致问题。

用户可能会更加困扰,Config设置零值、Nil(如果是指针)、或者其它值会有什么不同的效果。

我们再一次改变Config,用可变参数的形式:

情况有所好转,如果不想配置Config,用户也不需要给Config传入一个零值

Functional Options

更进一步,我们可以将Config修改得更加通用:

与上面的不同之处在于:所有的配置参数不再存在于 Config 对象中,而是存在于 Server 自己。

扩展阅读:https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html

于是,我们的API最后就变成了:

在此,我们提供一个更加完整地例子:

最后

总结一下,使用Function Options的方式来设计API,可以使得:

  • Functional options let you write APIs that can grow over time.
  • They enable the default use case to be the simplest.
  • They provide meaningful configuration parameters.
  • Finally they give you access to the entire power of the language to initialize complex values.

在API设计过程中,我们可以不断地问自己:

  • Can this be made simpler ?
  • Is that parameter necessary ?
  • Does the signature of this function make it easy for it to be used safely ?
  • Does the API contain traps or confusing misdirection that will frustrate ?

 

原文:https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis

码字很辛苦,转载请注明来自ChenJiehua《Functional options for friendly APIs》

评论