同樣都是使用介面,JAVA 和 Go 差距咋就這麼大呢?

happy_brother發表於2021-06-22

這篇文章將描述程式碼中經常使用的搶佔式介面模式,以及為什麼我認為在 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,而不會破壞向後相容性。介面是一種抽象,抽象有時很有用。然而,不必要的抽象會造成不必要的複雜化。在需要之前不要使程式碼過於複雜。

更多原創文章乾貨分享,請關注公眾號
  • 同樣都是使用介面,JAVA 和 Go 差距咋就這麼大呢?
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章