[英]How to manage cyclic dependencies when have interface and its implementation in different packages
I have my project structure looks like this:我的项目结构如下所示:
Structure of code:代码结构:
hypervisor
├── hypervisor.go
├── hyperv
│ └── hyperv.go
└── virtualbox
├── vbox.go
└── vboxprops.go
Source code:源代码:
//hypervisor/hypervisor.go
package hypervisor
type Hypervisor interface {
Start(vmName string) error
ListMounts(vmName string) ([]MountPath, error)
//....
}
type MountPath struct {
HostPath string
GuestPath string
}
func detect() (Hypervisor, error) {
return &virtualbox.Virtualbox{}, nil // <<1 HERE
}
// ... other code
And have another (nested) package :并有另一个(嵌套)包:
//hypervisor/virtualbox/vbox.go
package virtualbox
type Virtualbox struct {
}
func (*Virtualbox) Start(vmName string) error {
return vboxManage("startvm", vmName, "--type", "headless").Run()
}
func (*Virtualbox) ListMounts(vmName string) ([]hypervisor.MountPath, error) { // <<2 HERE
// ....
}
// ... other code
And as seen, of course, such code leads to import cycle not allowed
.正如所见,当然,此类代码会导致
import cycle not allowed
。 because of:因为:
hypervisor
pcakge referencing virtualbox.VirtualBox
type hypervisor
pcakge 引用virtualbox.VirtualBox
类型virtualbox
package referencing hypervisor.MountPath
typehypervisor.MountPath
类型的virtualbox
包I know if I move the struct MounthPath
to another package would solve the issue, but I don't think is the correct solution design-wise.我知道如果我将 struct
MounthPath
移动到另一个包会解决这个问题,但我认为这不是正确的解决方案设计。
Any suggestion?有什么建议吗?
One of easiest way I would do is to separate entities into entities
package for example (in this case: the Hypervisor
and Virtualbox
struct are entities or whatever you want to call it).我会做的最简单的方法之一是将实体分离到
entities
包中(在这种情况下: Hypervisor
和Virtualbox
结构是实体或任何你想称呼它的东西)。
This is most common design I think, so every struct that inner packages use will not cause cyclic deps.这是我认为最常见的设计,因此内部包使用的每个结构都不会导致循环 deps。
Example of usage: all time
package structs are on top package level.用法示例:所有
time
包结构都在顶级包级别。 time.Time{}
, time.Duration{}
, etc. time.Duration
does not sit on time/duration
package. time.Time{}
、 time.Duration{}
等time.Duration
不属于time/duration
包。
Following suggestions from Dave Cheney to define interfaces by the caller will avoid cycle dependencies in most cases.在大多数情况下,遵循 Dave Cheney 的建议由调用者定义接口将避免循环依赖。 But this will only solve flat data models.
但这只能解决平面数据模型。 In your case, you have nested entities ie., HyperVisor has fucntion which returns MounthPath.
在您的情况下,您有嵌套实体,即 HyperVisor 具有返回 MounthPath 的功能。 We can model this in two ways
我们可以通过两种方式对此进行建模
Define MouthPath in separate package (like you suggested).在单独的包中定义 MouthPath(如您所建议的)。 In addition, defining the interface in the virtualbox package will help in long term to provide alternative implementation for Hypervisor.
此外,在 virtualbox 包中定义接口将有助于为 Hypervisor 提供替代实现。
Let virtualbox define both Hypervisor and MounthPath as interface.让 virtualbox 将 Hypervisor 和 MounthPath 定义为接口。 One disadvantage is that the hypervisor implementing package use virtualbox.MouthPath interface to satisfy the interface when passed like below.
一个缺点是管理程序实现包使用 virtualbox.MouthPath 接口来满足如下传递时的接口。
//hypervisor/hypervisor.go //管理程序/管理程序.go
package hypervisor
type Hypervisor struct{
someField []virtualbox.MountPath
}
type MountPath struct { // this can be used as virtualbox.MountPath
hostPath string
guestPath string
}
func (m *MountPath) HostPath() string { return m.hostPath }
func (m *MountPath) GuestPath() string { return m.guestPath }
func detect() (Hypervisor, error) {
return &virtualbox.Virtualbox{}, nil // <<1 HERE
}
And have another package (Need not be nested)并有另一个包(不需要嵌套)
//hypervisor/virtualbox/vbox.go
package virtualbox
type Hypervisor interface {
Start(vmName string) error
ListMounts(vmName string) ([]MountPath, error)
//....
}
type MountPath interface {
HostPath() string
GuestPath() string
}
type Virtualbox struct {}
func (*Virtualbox) Start(vmName string) error {
return vboxManage("startvm", vmName, "--type", "headless").Run()
}
func (*Virtualbox) ListMounts(vmName string) ([]MountPath, error) { // <<2 HERE
// ....
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.