Go 函数类型与单一方法接口
如果接口只有一个方法,我应该使用函数类型吗 以下是两种方法的示例:Go 函数类型与单一方法接口,go,Go,如果接口只有一个方法,我应该使用函数类型吗 以下是两种方法的示例: type Delegate interface { | type Delegate func(x int) int Do(x int) int | } | | type Ap
type Delegate interface { | type Delegate func(x int) int
Do(x int) int |
} |
|
type App struct { | type App struct {
delegate Delegate | delegate Delegate
} | }
|
func (this *App) foo() { | func (this *App) foo() {
... | ...
y := this.delegate.Do(x) | y := this.delegate(x)
... | ...
} | }
|
func main() { | func main() {
delegate := &DelegateImpl{} | delegate := &DelegateImpl{}
app := &App{delegate} | app := &App{delegate.Process}
... | ...
} | }
测试:
type FakeDelegate { |
t *testing.T |
expectedX int |
result int |
} |
|
func (this *FakeDelegate) Do(x int) int { |
require.Equal(t, this.expectedX, x) |
return this.result |
} |
|
func TestAppFoo(t *testing.T) { | func TestAppFoo(t *testing.T) {
app := &App{} | app := &App{}
app.delegate = &FakeDelegate{t, 1, 2} | app.delegate = func(x int) int {
app.foo() | require.Equal(t, 1, x)
} | return 2
| }
| app.foo()
| }
看起来右边的代码(带有函数类型)的行数更少,尤其是在测试中。但在一般情况下,没有任何陷阱吗?
这是一个设计问题。接口提供了函数所没有的功能:动态分派。因此,如果以后您希望(可能是您自己的)客户机代码将所述函数应用于对象,并且设想该对象可能是程序中某个给定点的几种不同类型中的一种,请使用接口
赞成者:你可以变得灵活
缺点:
- 动态调度在执行时间上的开销很小。例如,您不希望在关键循环的中间出现这种情况
- 接口(如果可用)将随着系统的增长而使用,可能会以稍微出乎意料的方式使用。这意味着,大多数时候,您可以轻松地定义函数的责任范围,而接口的责任和类型签名应该作为设计决策进行仔细考虑
- 对于试图理解代码的读者来说,还有更多的知识间接性
尽管函数指针确实是开发人员管理的动态调度的一种形式,但在我看来,上面的推理仍然适用:寻求能够满足可预见需求的最简单解决方案。否则Go将成为Java。如果您确定委托永远不需要提供任何其他入口点(例如提供元信息),我会说坚持使用函数指针。我认为使用以下简单规则是合理的:
- 如果最有可能的实现工作在未在参数中传递的数据上,则使用接口。标准库中的示例:
接口,使用单个方法io.Reader
Read
- 否则,请使用函数。标准库中的示例:
,http.HandlerFunc
bufio.SplitFunc
我还发现好的名字有助于设计决策 方法可以作为函数指针传递,所以“在数据上工作”点实际上是无效的。实际上,这不是“函数与方法”,而是“函数类型与接口”。读卡器接口是否可以成为函数而不是单一方法接口?从技术上讲,这是可能的,但使用它将不太方便。
bufio.SplitFunc
是否可以是单个方法接口?是的,但是使用它的代码会变得更加冗长。你的问题没有单一的答案。