Go 語言中部分實現的接口 -技巧-
你好,我是小四,你情商高,也可以叫我四哥~
Go 語言不同於我們所知道的其他語言,比如 Java、C# 等。常常使用鴨子類型處理依賴關係。通過聲明一個本地接口,指定想要依賴的方法,但是不提供具體的實現,就像下面這樣:
// Notice that the interface does not even need to be exported
// for an outside dependency to satisfy it.
type doer interface {
Do()
}
func doStuff(d doer) {
d.Do()
}
任何實現了 Do() 方法的類型都是 doer 接口依賴實現。
按照慣例,Go 標準庫中的大多數接口都很小 (聲明的方法少)。Go 社區流行的一句諺語:
“接口越大,抽象能力越弱”
然而,在實際開發的時候,接口通常會包含很多個方法,所以違背了上面這條諺語。因此,看到一個接口聲明瞭 10-15 個方法並不奇怪。比如,當開發者想要抽象出數據庫的詳細操作時,就會面臨這種情況。
假設你遇到這種情況,並且需要提供一個函數的模擬實現,這個函數里面可能最多隻會使用其中的一兩個方法。你會實現其他方法來滿足這個接口嗎?
其中一個方法就是實現全部的方法,但是這種方式在測試的時候是不靈活的。
在我的實踐中,我發現一簡單的方法,只需要實現其中一個方法就能實現接口,就是通過接口嵌入的方式。
請看下面的例子:
type Store interface {
FindLatestOrder() (Order, error)
FindCustomerByID(id int) (Customer, error)
FindProductByID(id int) (Product, error)
// ... and many more
}
func doSomething(s Store) {
latestOrder, _ := s.FindLatestOrder() // error checks ignored for brevity
u, _ := s.FindCustomerByID(latestOrder.CustomerID)
fmt.Println(u.ID)
}
Store 接口包含很多方法,但是函數里面只用到了其中兩個。那我們怎麼才能在不實現接口所有方法的情況下,滿足函數的要求呢?
type dummyStore struct{}
func main() {
doSomething(&dummyStore{})
}
上面的代碼會導致編譯出錯。
然而,下面的代碼不僅可以編譯還能執行:
type dummyStore struct{
Store
}
func (ds *dummyStore) FindLatestOrder() (Order, error) {
return Order{CustomerID: 42, ProductID: 24}, nil
}
func (ds *dummyStore) FindCustomerByID(id int) (Customer, error) {
return Customer{ID: 42}, nil
}
// NOTE that we are not implementing FindProductByID
func main() {
doSomething(&dummyStore{})
}
那這是怎麼做到的?其實是因爲接口嵌入的原因,Store 接口嵌入結構體 dummyStore,結構體會自動獲得接口的所有方法,並且結構體還可以實現自己的方法。
因爲我們在實例化 dummyStore 時沒有提供 Store 的具體實現,所以它的值爲 nil,因此如果調用任何一個屬於 Store 的,但是 dummyStore 沒有實現的方法,將會導致錯誤 nil pointer dereference。
簡而言之,這就是如何在 Go 語言實現一個大型接口。這也是一個關於接口嵌入結構體的很好示例。但是,請謹慎使用。
via: https://preslav.me/2023/02/22/partially-implemented-interfaces-in-golang/
作者:Preslav Rachev
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/S0tGeQJ4iC_dZA9EHW5GZA