我知道以前曾多次以各種形式詢問過這個問題,但我似乎無法以我需要的方式實施我正在學習的內容。任何幫助表示贊賞。
我有一系列交易所,它們都實作了大致相同的 API。例如,它們每個都有一個GetBalance端點。然而,有些有一個或兩個獨特的東西需要在函式中訪問。例如,在呼叫它的余額 API 時exchange1需要使用 a ,而同時需要變數和變數。這是以后的重要說明。clientexchange2clientclientFutures
我的背景是普通的 OOP。顯然 Go 在很多方面都是不同的,因此我在這里被絆倒了。
我目前的實作和思路如下:
在exchanges模塊中
type Balance struct {
asset string
available float64
unavailable float64
total float64
}
type Api interface {
GetBalances() []Balance
}
在Binance模塊中
type BinanceApi struct {
key string
secret string
client *binance.Client
clientFutures *futures.Client
Api exchanges.Api
}
func (v *BinanceApi) GetBalance() []exchanges.Balance {
// Requires v.client and v.clientFutures
return []exchanges.Balance{}
}
在Kraken模塊中
type KrakenApi struct {
key string
secret string
client *binance.Client
Api exchanges.Api
}
func (v *KrakenApi) GetBalance() []exchanges.Balance {
// Requires v.client
return []exchanges.Balance{}
}
在main.go
var exchange *Api
現在我的想法是我應該能夠呼叫類似的東西exchange.GetBalance()并且它會使用GetBalance上面的函式。我還需要某種鑄造?我在這里很迷路。exchange可以是 Binance 或 Kraken——這在運行時決定。其他一些代碼基本上呼叫一個GetExchange函式,該函式回傳所需 API 物件的實體(已經在 BinanceApi/KrakenApi 中轉換)
我知道繼承和多型性不像其他語言那樣作業,因此我非常困惑。我很難知道這里需要去哪里。Go 似乎需要大量煩人的代碼來完成其他語言的動態作業??
uj5u.com熱心網友回復:
使用*exchanges.Api很奇怪。您想要實作給定介面的東西。底層型別是什么(無論是指標還是值接收器)并不重要,因此請exchanges.Api改用。
但是,還有另一個問題。在 golang 中,介面是隱式的(有時稱為鴨式介面)。一般來說,這意味著介面不是在實作它的包中宣告的,而是在依賴給定介面的包中宣告的。有人說你應該在回傳什么值方面是自由的,但在你接受的引數方面應該是限制性的。在您的情況下,這歸結為您擁有類似api包裹的東西,看起來有點像這樣:
package api
func NewKraken(args ...any) *KrakenExchange {
// ...
}
func NewBinance(args ...any) *BinanceExchange {
}
然后在你的其他包中,你會有這樣的東西:
package kraken // or maybe this could be an exchange package
type API interface {
GetBalances() []types.Balance
}
func NewClient(api API, otherArgs ...T) *KrakenClient {
}
因此,當有人查看此Kraken包的代碼時,他們可以立即分辨出需要哪些依賴項以及它適用于哪些型別。額外的好處是,如果 binance 或 kraken 需要額外的未共享的 API 呼叫,您可以進入并更改特定的依賴項/介面,而不會最終得到一個到處都在使用的龐大的集中式介面,但每次你最終只會使用界面的一個子集。
這種方法的另一個好處是在撰寫測??試時。有像gomockmockgen 這樣的工具,它們允許您通過執行以下操作快速生成單元測驗的模擬:
package foo
//go:generate go run github.com/golang/mock/mockgen -destination mocks/dep_mock.go -package mocks your/module/path/to/foo Dependency
type Dependency interface {
// methods here
}
然后運行go generate,它將在其中創建一個your/module/path/to/foo/mocks實作所需介面的模擬物件。在您的單元測驗中,匯入他的mocks包,您可以執行以下操作:
ctrl := gomock.NewController(t)
dep := mocks.NewDependencyMock(ctrl)
defer ctrl.Finish()
dep.EXPECT().GetBalances().Times(1).Return(data)
k := kraken.NewClient(dep)
bal := k.Balances()
require.EqualValues(t, bal, data)
長話短說
它的要點是:
- 介面就是介面,不要使用指向介面的指標
- 在依賴于它們(即用戶)的包中宣告介面,而不是實作(提供者)端。
- 只有在給定的包中真正使用它們時,才在介面中宣告方法。使用中央的、總體的界面使這更難做到。
- 與用戶一起宣告依賴介面使得自檔案代碼成為可能
- 單元測驗和模擬/存根更容易做,并且以這種方式自動化
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/537512.html
標籤:去遗产多态性
上一篇:__init__如何用于繼承
