在Go中修复导入周期

时间:2018-06-22 10:32:50

标签: go dependencies circular-dependency

因此,我要解决此导入周期。我有以下这种模式:

view/
- view.go
action/
- action.go
- register.go

通常的想法是,动作是在视图上执行的,并由视图执行:

// view.go
type View struct {
    Name string
}

// action.go
func ChangeName(v *view.View) {
    v.Name = "new name"
}

// register.go
const Register = map[string]func(v *view.View) {
    "ChangeName": ChangeName,
}

然后在view.go中调用它:

func (v *View) doThings() {
    if action, exists := action.Register["ChangeName"]; exists {
        action(v)
    }
}

但这会导致循环,因为View依赖于Action包,反之亦然。我该如何解决 这个周期?有其他解决方法吗?

2 个答案:

答案 0 :(得分:4)

导入周期表明设计上存在根本错误。广义上讲,您正在查看以下内容之一:

  • 您正在混合担忧。也许view根本不应该访问action.Register,或者也许action不应该负责更改视图的名称(或两者)。这似乎是最有可能的。
  • 您所依赖的对象是应该依赖接口并注入对象的对象。例如,它可以直接在action.Register内定义的接口类型上调用方法,而不是在视图中直接访问view,并在构造时将其注入View对象中。
  • 您需要一个或多个其他单独的程序包来容纳viewaction程序包都使用的逻辑,但是两者都不调用。

通常来说,您希望构建一个应用程序,以便拥有三种基本类型的软件包:

  1. 完全独立的软件包,不引用其他任何第一方软件包(它们当然可以引用标准库或其他第三方软件包)。
  2. 仅内部依赖项为上述类型1的逻辑包,即完全独立的包。这些程序包不应相互依赖或依赖于以下类型3的程序包。
  3. “接线”程序包,主要与逻辑程序包交互,并处理实例化,初始化,配置和依赖性注入。这些可以依赖于其他3类软件包以外的任何其他软件包。您应该只需要很少的这种类型的软件包-通常只有一个main,但对于更复杂的应用程序则偶尔需要两个或三个。

答案 1 :(得分:0)

导入周期是设计错误的结果。双向相互依赖的结构必须位于同一程序包中,否则将发生导入周期。顺便说一下,Go并不是唯一有此限制的编程语言。例如,它也存在于C ++和Python中。