Golang中interface的使用建议

https://medium.com/@mbinjamil/using-interfaces-in-go-the-right-way-99384bc69d39

分享的是一个关于Golang中interface的正确使用方法。

讲道理在medium上找一篇对我有所帮助的文章还挺难的,大多是比较简单的教程,或者是空谈与介绍。

Accept Interfaces, Return Structs#

接口是一组对象的方法的抽象集合,所以我们在实现具体方法前,不应该先考虑如何去定义interface。我们应该在观察消费者行为的时候,抽象消费者所需要的方法,而不是在实现的时候考虑如何去抽象。

Go Code Review Comments里提到一点:

Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values.

也就是,一个接口应该出现在消费者的package里,而不是实现的package里。

Don’t Do this#

package tcp

type Server interface {
    Start()
}

type server struct { ... }

func (s *server) Start() { ... }

func NewServer() Server { 
    return &server{ ... } 
}
package consumer
import “tcp”	//耦合

func StartServer(s tcp.Server) { 
    s.Start() 
}

这是非常不推荐的interface的用法,因为它不是为了抽象的目的而定义的,而且这种写法将消费者包耦合到了实施者包。

Do This Instead#

package tcp
type Server struct { ... }
func (s *server) Start() { ... }
func NewServer() Server { return &Server{ ... } }
package consumer
type Server interface {
    Start() 
}
func StartServer(s Server) { s.Start() }

这样的话就把实现package跟消费package解耦了,消费者只需要关心,这个interface所拥有的方法,而不需要关心其他。

Go Standard Library#

这部分主要是提及在golang standard中,上述原则的体现。

像在io包中

type Reader interface {
    Read(p []byte) (n int, err error)
}
func Copy(dst Writer, src Reader) (written int64, err error)

还有HTTP包中

type Handler interface { 
    ServeHTTP(ResponseWriter, *Request) 
} 
func ListenAndServe(addr string, handler Handler) error

Interface Segregation Principle#

这部分是讲上述原则其实也是为了SOLID原则,即其中的 Interface Segregation Principle也就是接口隔离原则。

“Clients should not be forced to depend on interfaces that they do not use.”

同时,消费者应该只接收含有他们所关心方法的接口。

// os.File contains many unrelated methods 
func Save(f *os.File, doc *Document) error 
// io.ReadWriteCloser contains unrelated Read() and Close() methods 
func Save(rwc io.ReadWriteCloser, doc *Document) error
// io.Writer contains only one method Write() that is required 
func Save(w io.Writer, doc *Document) error

第一个方法,os.File包含了太多用户不需要的函数、

第二个方法,io.ReadWriteCloser包含了与定义不相关的Read()和CLose()

第三个方法,正好是我们所需要的。

当我们在使用它们之前定义接口时,即在生产者包中,它们通常是包含许多方法的大型接口。此外,这些接口将添加新方法,因为实现会随着时间而变化。这意味着使用相同接口的所有消费者更有可能拥有与其功能无关的方法。

因此,仅在需要使用接口时才定义接口意味着我们遵循接口隔离原则。并且通过遵循这个原则,我们可以防止为多个职责定义方法的臃肿接口,从而产生更易于维护的 Go 代码

posted @   ViKyanite  阅读(97)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示
主题色彩