【问题标题】:Package decoupling in gogo中的包解耦
【发布时间】:2018-03-02 20:53:02
【问题描述】:
我们都知道依赖注入使包解耦。
但是我对 go 中依赖注入的最佳实践有点困惑。
让我们假设包用户需要访问配置包。
我们可以将 Config 对象传递给 User 方法。这样,只要新代码解析接口,我就可以更改 Config 包功能。
另一种方法是直接调用 Config 包方法,在这种情况下,只要方法名称保持不变,我也可以更改 Config 代码。像这样
更新:
这两种方法有什么不同:
package User
func foo(config ConfigObject) {
config.Foo()
}
还有这个:
package User
import Config
func foo() {
config.Foo()
}
【问题讨论】:
标签:
go
design-patterns
dependency-injection
solid-principles
decoupling
【解决方案1】:
在方法的config 参数上调用config.Foo 意味着您收到某个结构的实例(可能实现接口Config)并在该实例/接口上调用方法Foo。将其视为在 OO 术语中调用对象的方法:
package user
func foo(cfg config.Config) {
cfg.Foo()
}
在导入config 包后调用config.Foo 意味着您正在调用包config 的函数Foo,而不是任何对象/结构/接口。将其视为没有任何对象的纯过程编程:
package user
import config
func foo() {
config.Foo()
}
后者与依赖注入无关,如果Config是一个接口,前者可能构成其中的一部分。
另一方面,依赖注入在 Go 中遵循与其他语言相同的规则:
接受接口,提供实现
因为在 Go 中,结构隐式而不是显式地满足接口(Java 就是这种情况)
- 接受值的代码只需要知道接口并导入即可;
- 实现它的代码甚至不需要了解接口(它可能恰好满足它);
- 将 impl 提供到接受
界面显然需要两者都知道。
对于您的示例,这意味着:
package config
type Config interface {
Foo() string
}
package foo
type Foo struct{}
func (f *Foo) Foo() string {
return "foo"
}
package boo
type Boo struct{}
func (b *Boo) Foo() string {
return "boo"
}
package main
func foo(cfg config.Config) string{
return cfg.Foo()
}
func main() {
// here you inject an instance of Foo into foo(Config)
log.Print(foo(&foo.Foo{}))
// here you inject an instance of Boo into foo(Config)
log.Print(foo(&boo.Boo{})
}
打印
2018/03/03 13:32:12 富
2018/03/03 13:32:12 嘘