写点什么

同样都是使用接口,JAVA 和 Go 差距咋就这么大呢?

发布于: 2 小时前
同样都是使用接口,JAVA和Go差距咋就这么大呢?

这篇文章将描述代码中经常使用的抢占式接口模式,以及为什么我认为在 Go 中遵循这种模式通常是不正确的。

什么是抢占式接口

接口是一种描述行为的方式,存在于大多数类型语言中。抢占式接口是指开发人员在实际需要出现之前对接口进行编码。一个示例可能如下所示。


type Auth interface {  GetUser() (User, error)}
type authImpl struct { // ...}func NewAuth() Auth { return &authImpl}
复制代码

抢占式接口何时有用

抢占接口通常用于在 Java 中,并且大获成功,这是大部分程序员的想法。相信,很多 Go 开发者也是这么认为的。这种用法主要区别在于 Java 具有显式接口,而 Go 是隐式接口。让我们看一些示例 Java 代码,这些代码显示了如果不使用 Java 中的抢占式接口可能会出现的困难。


// auth.javapublic class Auth {  public boolean canAction() {    // ...  }}// logic.javapublic class Logic {  public void takeAction(Auth a) {    // ...  }}
复制代码


现在假设您要更改 Logic 的 takeAction 方法中的参数 Auth 类型的对象,只要它具有 canAction()方法即可。不幸的是,你不能。Auth 没有在其中实现带有 canAction()的接口。你现在必须修改 Auth 为其提供一个接口,然后您可以在 takeAction 中接受该接口,或者将 Auth 包装在一个除了实现的方法之外什么都不做的类中。即使 logic.java 定义了一个 Auth 接口以在 takeAction()中接受,也可能很难让 Auth 实现该接口。您可能无权修改 Auth,或者 Auth 可能位于第三方库中。也许 Auth 的作者不同意你的修改。也许在代码库中与同事共享 Auth,现在需要在修改之前达成共识。这是希望的 Java 代码。


// auth.javapublic interface Auth {  public boolean canAction()}// authimpl.javaclass AuthImpl implements Auth {}// logic.javapublic class Logic {  public void takeAction(Auth a) {    // ...  }}
复制代码


如果 Auth 的作者最初编码并返回一个接口,那么你在尝试扩展 takeAction 时,永远不会遇到问题。它自然适用于任何 Auth 接口。在具有显式接口的语言中,以后你会感谢过去的自己使用了抢占式接口。

为什么这在 Go 中不是问题

让我们在 Go 中设置相同的情况。


// auth.go type Auth struct { // ... }// logic.go func TakeAction(a *Auth) {   // ... }
复制代码


如果 logic 想要使 TakeAction 通用,则 logic 所有者可以单方面执行此操作,而不会打扰其他人。


// logic.go type LogicAuth interface {   CanAction() bool }func TakeAction(a LogicAuth) {   // ... }
复制代码


请注意 auth.go 不需要更改。这是使抢占式接口不再需要的关键所在。

Go 中抢占式接口的意外副作用

Go 的接口定义都是很小,但很强大。在标准库中,大多数接口定义都是单一方法。这允许最大的重用,因为实现接口很容易。当程序员对像上面的 Auth 这样的抢占式接口进行编码时,接口的方法数量往往会激增,这使得接口(可交换实现)的全部意义更难以实现。

Go 中接口的最佳用法

Go 的一个很好的经验法则是-接受接口,返回结构体。接受接口为您的 API 提供了最大的灵活性,返回结构体允许调用者快速导航到正确的函数。


即使你的 Go 代码接受结构体并返回结构体以启动,隐式接口也允许您稍后扩展你的 API,而不会破坏向后兼容性。接口是一种抽象,抽象有时很有用。然而,不必要的抽象会造成不必要的复杂化。在需要之前不要使代码过于复杂。

用户头像

还未添加个人签名 2018.04.27 加入

已出版《Go语言极简一本通》 B站ID:面向加薪学习,公众号:面向加薪学习 加微信write_code_666,进群,可以和更多小伙伴交流,专注于Go|Java|Flutter|前端|小程序|移动端|项目管理|软件架构。

评论

发布
暂无评论
同样都是使用接口,JAVA和Go差距咋就这么大呢?