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

13161658867 · 2021-06-22 16:13:10 · 3143 次点击 · 预计阅读时间 2 分钟 · 大约8小时之前 开始浏览    
这是一个创建于 2021-06-22 16:13:10 的文章,其中的信息可能已经有所发展或是发生改变。

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

什么是抢占式接口

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

type Auth interface {
  GetUser() (User, error)
}

type authImpl struct {
  // ...
}
func NewAuth() Auth {
  return &authImpl
}

抢占式接口何时有用

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

// auth.java
public class Auth {
  public boolean canAction() {
    // ...
  }
}
// logic.java
public 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.java
public interface Auth {
  public boolean canAction()
}
// authimpl.java
class AuthImpl implements Auth {
}
// logic.java
public 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,而不会破坏向后兼容性。接口是一种抽象,抽象有时很有用。然而,不必要的抽象会造成不必要的复杂化。在需要之前不要使代码过于复杂。

3.jpg


有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3143 次点击  ∙  1 赞  
加入收藏 微博
2 回复  |  直到 2021-06-26 18:57:05
sanrentai
sanrentai · #1 · 4年之前

这篇文章读起来有些费力。 这允许最大的重用,因为实现接口很容易。当程序员对像上面的Auth这样的抢占式接口进行编码时,接口的方法数量往往会激增,这使得接口(可交换实现)的全部意义更难以实现。

没明白副作用在哪呢?

13161658867
13161658867 · #2 · 4年之前
sanrentaisanrentai #1 回复

这篇文章读起来有些费力。 这允许最大的重用,因为实现接口很容易。当程序员对像上面的Auth这样的抢占式接口进行编码时,接口的方法数量往往会激增,这使得接口(可交换实现)的全部意义更难以实现。 没明白副作用在哪呢?

对于type Auth interface 这个接口,很容易方法激增,那么就使得接口(可交换实现)的全部意义更难以实现。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传