【GOLANG】函数式选项模式(Functional Options Pattern)

在牛客摸鱼刷贴的时候看到一个老哥的面经里面记了一条 func的自定义参数,印象中好像没有在我看过的面经中出现过。image.png

于是通过万能的互联网,找到了这个问题究竟是要问什么:函数式选项模式(Functional Options Pattern)。

这个函数式选项模式的出现背景我也了解了一下: golang 开发者遇到的许多问题之一是尝试将一个函数的参数设置为可选. 这是一个非常常见的用例, 有些对象应该使用一些基本的默认设置来开箱即用, 并且你偶尔可能需要提供一些更详细的配置。 在很多语言中这很容易; 在 c 族语言中, 可以使用不同数量的参数提供相同函数的多个版本; 在像 php 这样的语言中, 可以给参数一个默认值,并在调用方法时忽略它们. 但是在 golang 中, 这两种方式你哪个也用不了. 那么你如何创建一个函数, 用户可以指定一些额外的配置?有很多可能的方法可以做到这一点, 但是大多数都不能满足要求, 或者需要在服务端的代码中进行额外的检查和验证, 或者通过传递额外的客户端不关心的参数来为客户端做额外的工作。

Option模式的优缺点
优点:
1. 支持传递多个参数,并且在参数个数、类型发生变化时保持兼容性
2. 任意顺序传递参数
3. 支持默认值
4. 方便拓展
缺点:
1. 增加许多function,成本增大
2. 参数不太复杂时,尽量少用

对于我这种迟钝型选手其实看完定义和优缺点后并没有什么感受,甚至还有点懵逼。不过在看了网上别人贴的demo代码后醍醐灌顶!
因为最近在研究ipfs的存储方案和查找方案,有事没事就翻ipfs的源码,而且恰恰好是今天!在go-ipfs-api这个库中,我无意间瞄到了这个写法!于是我连忙找到了下边的代码

type AddOpts = func(*RequestBuilder) error

func (s *Shell) Add(r io.Reader, options ...AddOpts) (string, error) {
	fr := files.NewReaderFile(r)
	slf := files.NewSliceDirectory([]files.DirEntry{files.FileEntry("", fr)})
	fileReader := files.NewMultiFileReader(slf, true)

	var out object
	rb := s.Request("add")
	for _, option := range options {
		option(rb)//这里就是使用的选项模式!
	}
	return out.Hash, rb.Body(fileReader).Exec(context.Background(), &out)
}
复制代码

这段代码是终端调用add命令向ipfs上传文件的源码,结合整个源码内容来看,终端的请求在构造过程中会因为需求不同,Request带的参数会也是不同的对应的内容,不同的数据操作。不得不说这样做确实非常符合开闭原则,对扩展非常的友好!而且k-v形式的参数也不需要严格要求顺序,参数本身也作为一个可选项,简直是完美契合了选项模式!

想不到摸鱼还摸到个之前没了解过的知识点,甚是高兴。

猜你喜欢

转载自juejin.im/post/7109801915067678750