【问题标题】:How to solve this Go cyclical dependency如何解决这个 Go 循环依赖
【发布时间】:2018-02-22 10:00:10
【问题描述】:

我一直在为一门课程学习 Go,我对这门语言感到非常兴奋,它对 Web 服务真的非常有用。

所以,我一直在为最终项目编写这个 CRUD restful API,并且一直在该死的循环依赖问题中运行。我已经研究并阅读了解决它的方法,并将在这里发布只是为了它,但首先我遇到的问题是:

routes 需要了解 handlers 包中的处理函数,而后者又需要了解 user 包中的 user 结构。 em>model 包,为了发送带有链接的注册电子邮件需要了解 routes 路径

古典 A -> B -> C -> A

现在,我正在尝试使用 MVC 和三层架构编写此 API,我希望我的路由位于控制器包中,我的处理程序位于业务逻辑包中,我的用户位于模型包中。这也是需要的,因为我有超过 43 个模型类,我需要把它们整理好并放在他们的包里。

好的,我找到了解决办法

1 - 把每个人都放在同一个包上:这是我迄今为止一直在做的,但由于显而易见的原因,这是一个非常糟糕的解决方案。

2- 在调用函数时传递 user 需要的任何参数:这将是一个很好的解决方案,但由于正在调用的函数而不起作用from user 来自一个接口实现,因为它必须是一个泛型调用,并且在有人说我的问题是因为我在 go 中强制泛型之前,太糟糕了,我需要那个泛型,我不会写超过 160 个 crud 函数。函数的重点是避免代码重复。

3- 使用另一个接口创建另一个包,并让它有一个处理程序和用户的实例,并让它从一个到另一个传递参数:尽管上面提到了原因,但需要通用,这听起来像是一个不必要的复杂解决方案,我拒绝相信这是比循环依赖更好的设计。

底线问题:当 C 需要知道来自 A 的信息并且必须尊重泛型时,如何解决这种依赖关系

如果您需要,我可以在此处发布一些代码,但当这是一个更高级别的问题时,我看不到特定代码的相关性。

EDIT:解决了我的依赖问题。谢谢大家的cmets和回答,因为它让我找到了答案。我认为我没有实施任何建议的解决方案,但它确实教会了我很多关于如何解决问题的知识,如果不是出于我自己的限制,它们都是非常可接受和可行的解决方案。 '不想将任何东西传递给用户。 对于任何试图解决他们自己的依赖问题的人,我能够收集到的是,在我的情况下,C 不是让 A 向 A 询问一些东西,而是在它必须询问之前给 C 任何它需要的东西,这意味着将信息传递给他.

唉,这不是我的解决方案,我所做的是从 A 中删除信息并将信息提供给 Z,现在 A 和 C 都在询问 Z 的路径信息,这只是一个地图,坐在那里地图喜欢和持有信息。 谢谢大家

【问题讨论】:

  • AC 应该是这里的“顶级”包吗?即使您没有“main”包,您也需要在概念上将顶层视为与“main”相同的方式,没有其他东西可以导入它。
  • 疯狂猜测:用户不需要(也可能不需要)了解路线。它只需要一些 URL,它是一个字符串。从处理程序传递下来。或者,让用户依赖于某个接口,该接口在模型中定义并在其他地方实现。话虽如此,您会发现按类型(模型、处理程序等)组织事物是愚蠢的。改为按域组织(包用户、包博客等)。如果项目很小,单个包也完全可以。
  • @JimB 感谢您的提示,我将尝试重新想象解决方案,因为它是服务器,我承认我从未想过它。我猜主要是路由包,因为它们是捕获http请求的包。
  • @peter 我无法传递 url,这将是我猜想的最佳解决方案(第 2 点解释了为什么我不能传递它)。我明白你在说什么,而不是将路由集中在一个包中,每个模型都会知道处理它们的路由。这听起来是一个非常有趣的方法......我将进一步探索

标签: go


【解决方案1】:

您有一些选择,并且您已经找到了其中的一些。处理的主要方法是:

  • 重构您的设计,将循环变成一棵树。由于您的要求,这并不真正适用于您的情况。
  • 重构您的设计以使用某种依赖注入(这是您问题中的第二个选项)。这是完全可行的,而且可能是最干净、最简单的。
  • 重构您的设计以采用本地声明的接口。这是选项 3 的更符合 Go 习惯的版本。因为 Go 中的接口是鸭子类型的,所以您可以在使用它的地方定义它,而不是在哪里实现它。所以你的用户包可以为“一个给我我需要的 URL 的东西”定义一个单一方法接口,它永远不需要引用实现该接口的包。

【讨论】:

  • 感谢您的回复,但我真的不太明白您的第二点和第三点。两者看起来有点像,都有一个可以传递所需信息的接口。即使接口是在用户本地声明的,但实现它的人必须将其传递给需要 url 的用户函数,当我试图保留通向用户的函数时,我怎么能有人传递一些东西;s 函数调用泛型?我认为我的解释有点混乱,如果您愿意,我可以发布代码。
  • 我没有说第二个选项中的接口。只是你的函数可以接收它需要的东西,而不是去得到它需要的东西。
  • 我已经阅读了依赖注入,现在我看到了这两个选项之间的区别,但是有没有办法注入依赖而不必传递函数调用?该函数是用于模拟泛型的接口的一部分,因此我没有在其中传递任何参数。对于第三个选项,实现接口的人如何向用户提供信息,通过作为参数传递来保存
  • 用户必须将某些东西作为参数。这样可以避免不必要的依赖和循环依赖。
猜你喜欢
  • 2019-02-23
  • 1970-01-01
  • 2012-03-15
  • 2016-09-21
  • 2021-07-12
  • 1970-01-01
相关资源
最近更新 更多