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