1 回答
TA贡献1877条经验 获得超1个赞
使用*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)
长话短说
它的要点是:
接口就是接口,不要使用指向接口的指针
在依赖于它们(即用户)的包中声明接口,而不是实现(提供者)端。
只有在给定的包中真正使用它们时,才在接口中声明方法。使用中央的、总体的界面使这更难做到。
与用户一起声明依赖接口使得自文档代码成为可能
单元测试和模拟/存根更容易做,并且以这种方式自动化
- 1 回答
- 0 关注
- 106 浏览
添加回答
举报