go中的包解耦
Package decoupling in go
我们都知道依赖注入使包解耦。
但是我对 go 中依赖注入的最佳实践有点困惑。
让我们假设包用户需要访问配置包。
我们可以将 Config 对象传递给 User 方法。这样,只要新代码解析接口,我就可以更改 Config 包功能。
另一种方法是直接调用 Config 包方法,在这些情况下,只要方法名称保持不变,我也可以更改 Config 代码。像这样
更新:
这两种方法有什么不同:
package User
func foo(config ConfigObject) {
config.Foo()
}
还有这个:
package User
import Config
func foo() {
config.Foo()
}
在方法的 config
参数上调用 config.Foo
意味着您收到某个结构的实例(可能实现接口 Config
)并调用方法 Foo
在那 instance/interface 上。将此视为在 OO 术语中调用对象的方法:
package user
func foo(cfg config.Config) {
cfg.Foo()
}
调用 config.Foo
已导入 config
包意味着您正在调用包 config
的函数 Foo
,而不是任何 object/struct/interface 的函数。将此视为没有任何对象的纯过程编程:
package user
import config
func foo() {
config.Foo()
}
后者与依赖注入无关,前者如果Config
是接口可能构成其中的一部分
另一方面,依赖注入在 Go 中通常遵循与其他语言相同的规则:
accept interfaces, supply implementations
因为在 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 foo
2018/03/03 13:32:12 boo
我们都知道依赖注入使包解耦。
但是我对 go 中依赖注入的最佳实践有点困惑。
让我们假设包用户需要访问配置包。
我们可以将 Config 对象传递给 User 方法。这样,只要新代码解析接口,我就可以更改 Config 包功能。
另一种方法是直接调用 Config 包方法,在这些情况下,只要方法名称保持不变,我也可以更改 Config 代码。像这样
更新:
这两种方法有什么不同:
package User
func foo(config ConfigObject) {
config.Foo()
}
还有这个:
package User
import Config
func foo() {
config.Foo()
}
在方法的 config
参数上调用 config.Foo
意味着您收到某个结构的实例(可能实现接口 Config
)并调用方法 Foo
在那 instance/interface 上。将此视为在 OO 术语中调用对象的方法:
package user
func foo(cfg config.Config) {
cfg.Foo()
}
调用 config.Foo
已导入 config
包意味着您正在调用包 config
的函数 Foo
,而不是任何 object/struct/interface 的函数。将此视为没有任何对象的纯过程编程:
package user
import config
func foo() {
config.Foo()
}
后者与依赖注入无关,前者如果Config
是接口可能构成其中的一部分
另一方面,依赖注入在 Go 中通常遵循与其他语言相同的规则:
accept interfaces, supply implementations
因为在 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 foo
2018/03/03 13:32:12 boo