“承受接口、返回构造”的个别准则,我在前一篇文章中写到,也屡次在代码评审时向共事介绍,但常常遇到“为什么”的疑难。特地是因为这不是一条硬性规定。该想法的关键在于放弃灵活性的同时防止事后形象,并了解何时扭转它。
事后形象使零碎变得复杂
计算机科学畛域的任何问题都能够通过减少一个间接的中间层来解决,当然,间接过多的问题除外 – David J. Wheeler
软件工程师喜爱形象。就我集体而言,从未见过编写代码比创立形象更投入的共事。Go 中,接口形象脱离了构造,该间接层甚至没有最低档次的嵌入复杂性。遵循软件设计 您不会用到它 的哲学,在须要之前制作这种复杂性毫无意义。函数调用返回接口的一个常见起因是让用户专一于函数凋谢的 API。因为有隐式接口,Go 不须要这样做。构造的 public function iu 就是其 API。
总是当 真正 须要时 [形象],不要当 预感 须要时 [形象]。
某些语言要求你预感将来须要的每个接口。隐式接口的一大长处是,它们容许预先进行优雅的形象,而无需事后进行形象。
因人而异的“须要”
当真正须要时
如何定义何时须要形象?对于返回类型,这很容易。你是编写该函数的人,因而您确切晓得何时须要将返回值形象。
对于函数输出,需要不在你的管制范畴之内。你可能认为 database struct 就足够了,但用户可能须要用其余货色装璜它。就算不是不可能,预测每个人应用你的函数的状态也是很艰难的。可能准确管制输入,但无奈预测用户输出。相比对输入的抽象化,这种不均衡造成了对输出的抽象化更强烈的并重。
去除不必要的代码细节
简化的另一方面是去除不必要的细节。函数就像烹饪食谱:给定输出,就会失去一个蛋糕!没有食谱会列出不须要的配料。相似地,函数也不应该列出不须要的输出。你如何看以下函数?
func addNumbers(a int, b int, s string) int {return a + b}
对于大多数程序员来说,很显著,参数 s 不失当。当参数是构造时,却不太显著。
type Database struct{ }
func (d *Database) AddUser(s string) {...}
func (d *Database) RemoveUser(s string) {...}
func NewUser(d *Database, firstName string, lastName string) {d.AddUser(firstName + lastName)
}
就像配料太多的食谱一样,NewUser 接管一个能够做太多事件的 Database 对象。它只须要 AddUser,但接管的参数还有 RemoveUser。应用接口创立的函数,能够只依赖于必须。
type DatabaseWriter interface {AddUser(string)
}
func NewUser(d DatabaseWriter, firstName string, lastName string) {d.AddUser(firstName + lastName)
}
Dave Cheney 在形容 接口隔离准则 时 写到了这一点。他还形容了限度输出的其余长处,值得一读。让人了解这个想法的总指标是:
后果同时是一个函数,它的要求是最具体的——它只须要一个可写的货色——并且它的函数是最通用的
我只想补充一点,下面的函数 addNumber 显然不应该有参数字符串 s,函数 NewUser 现实状况下不须要能够删除用户的 database。
总结起因并审查例外
次要起因如下:
- 去除不须要的形象
- 用户对函数输出需要是含糊的
- 简化函数输出
以上起因还容许咱们定义规定的例外情况。例如,如果函数须要返回多种类型,那么显然返回须要定义为接口。相似地,如果函数是公有的,那么函数输出便并不含糊,因为你能够管制它,所以偏向于非事后形象。对于第三条规定,go 没有方法形象出 struct 成员的值。因而,如果你的函数须要拜访构造体成员(而不仅仅是构造体上的函数),那么您将被迫间接承受构造体。
原文:What“accept interfaces, return structs”means in Go
本文作者 :cyningsun
本文地址 :https://www.cyningsun.com/08-…
版权申明:本博客所有文章除特地申明外,均采纳 CC BY-NC-ND 3.0 CN 许可协定。转载请注明出处!