【发布时间】:2021-01-20 00:39:28
【问题描述】:
Go 中的一个常见模式是使用依赖注入作为绕过循环导入的手段。
例如,here is a very short code snippet 定义了两个对象,House 和 Garage。使用了Dispatcher 抽象,以便他们可以随意调用彼此的方法。 (Dispatcher 被注入到每个对象中。)
到目前为止,一切都很好。
在这段代码 sn-p 的基础上,假设我编写了一个 House 的新方法,它需要 10 个参数:
type HouseDispatcher interface {
// This matches all of the methods of house.House
SetThermostat(temp int)
PrepareBedroom(arg1 int, arg2 int64, arg3 int32, arg4 uint64, arg5 uint32, arg6 string, arg7 rune, arg8 int, arg9 int, arg10 int)
}
这段代码有异味,所以我们需要将它重构为一个对象:
type BedroomData struct {
arg1 int
arg2 int64
arg3 int32
arg4 uint64
arg5 uint32
arg6 string
arg7 rune
arg8 int
arg9 int
arg10 int
}
type HouseDispatcher interface {
// This matches all of the methods of house.House
SetThermostat(temp int)
PrepareBedroom(data BedroomData)
}
好多了!但是 BedroomData 结构体存在于 House.go 文件中是有意义的,紧挨着与房屋相关的所有其他代码。
所以当我们在 Dispatcher 中搭建方法时,我们不得不这样编码:
type HouseDispatcher interface {
// This matches all of the methods of house.House
SetThermostat(temp int)
PrepareBedroom(data interface{})
}
现在我们已经失去了类型安全性。
我们可以通过在Dispatcher 中复制BedroomData 结构定义来恢复类型安全性,但现在我们违反了 DRY - 这两个结构可能不同步并导致灾难性的运行时错误。
那么解决办法是什么?
【问题讨论】:
-
将结构体放入
model包中,并使用它定义接口和实现。 -
这很聪明,应该可以解决问题。虽然,房子包中没有所有与房子相关的数据很烦人。有更好的解决方案吗?
-
显而易见的是:将
House和Garage放入同一个包中。但是,将接口和模型放入单独的包而不是实现的想法是一种常见的模式。 -
虽然我可以效仿你的做法,但这似乎是强迫的,不切实际的。我从未见过这样的代码。你有这个问题困扰你的真实例子吗?
标签: go dependency-injection dry circular-dependency