首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Go中的接口管理

Go中的接口管理
EN

Stack Overflow用户
提问于 2022-11-15 10:09:26
回答 1查看 91关注 0票数 -1

我知道以前很多次都以各种形式问过这个问题,但我似乎无法以我所需要的方式来实现我正在学习的东西。任何帮助都是非常感谢的。

我有一系列的交换,它们都实现了大致相同的API。例如,它们每个都有一个GetBalance端点。但是,有些功能中有一到两个独特的东西需要访问。例如,exchange1在调用它的balance时需要使用client,而exchange2需要同时使用client变量和clientFutures变量。这是以后的一个重要注意事项。

我的背景是正常的。显然围棋在很多方面是不同的,所以我在这里被绊倒了。

我目前的实施和想法如下:

exchanges模块中

代码语言:javascript
复制
type Balance struct {
    asset       string
    available   float64
    unavailable float64
    total       float64
}

type Api interface {
    GetBalances() []Balance
}

Binance模块中

代码语言:javascript
复制
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模块中

代码语言:javascript
复制
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

代码语言:javascript
复制
var exchange *Api

现在我的想法是,我应该能够调用类似于exchange.GetBalance()的东西,它将从上面使用GetBalance函数。我也需要一些演员吗?我在这里迷路了。exchange可以是Binance,也可以是Kraken--在运行时决定。其他一些代码基本上调用一个GetExchange函数,该函数返回所需API对象的一个实例(已经在BinanceApi/KrakenApi中插入)

我知道继承和多态性不像其他语言那样工作,因此我完全搞不懂。我很想知道这里该去哪。Go似乎需要大量烦人的代码,这是其他语言在运行中所必需的。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-15 10:32:11

使用*exchanges.Api是相当奇怪的。您需要实现给定接口的东西。底层类型是什么(无论是指针还是值接收者)并不重要,所以使用exchanges.Api代替。

不过,还有另一个问题。在golang中,接口是隐式的(有时称为鸭子类型的接口)。一般来说,这意味着接口不是在实现它的包中声明的,而是在依赖于给定接口的包中声明的。有些人说,你应该自由地看待你所返回的价值观,但在你所接受的论点方面,你应该是限制性的。这可以归结为,在您的情况下,您将有类似于api包的东西,看起来有点像这样:

代码语言:javascript
复制
package api

func NewKraken(args ...any) *KrakenExchange {
   // ...
}

func NewBinance(args ...any) *BinanceExchange {
}

然后在你的其他包里,你会有这样的东西:

代码语言:javascript
复制
package kraken // or maybe this could be an exchange package

type API interface {
    GetBalances() []types.Balance
}

func NewClient(api API, otherArgs ...T) *KrakenClient {
}

因此,当有人查看这个Kraken包的代码时,他们可以立即判断所需的依赖项,以及它所使用的类型。另外的好处是,如果二进制或kraken需要额外的未共享的API调用,您可以进入并更改特定的依赖项/接口,而不会最终得到一个正在各地使用的庞大的集中化接口,但每次您只使用接口的一个子集。

这种方法的另一个好处是在编写测试时。有像gomock和mockgen这样的工具,这些工具允许您简单地通过以下操作为单元测试快速生成模拟:

代码语言:javascript
复制
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中创建一个模拟对象,实现所需的接口。在单元测试中,导入he mocks包,您可以这样做:

代码语言:javascript
复制
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)

TL;DR

它的主旨是:

interfaces

  • Declare接口是接口,不要在依赖于它们的包(即用户)中使用指向它们的指针,而不是在实现(提供程序)端。

  • 只在给定的包中真正使用它们时才在接口中声明方法。使用一个中心的、总体的接口使得这很难做到。

  • 将依赖接口声明在用户的旁边,以便进行自文档化的代码

  • 单元测试和嘲弄/顽固性操作,并通过

实现自动化。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74443828

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档