2 回答
TA贡献1827条经验 获得超9个赞
例如,我会做的一种最简单的方法是将实体分成entities
包(在这种情况下:Hypervisor
和Virtualbox
结构是实体或任何你想调用的东西)。
这是我认为最常见的设计,因此内部包使用的每个结构都不会导致循环依赖。
使用示例:所有time
包结构都在顶级包级别。time.Time{}
,time.Duration{}
等time.Duration
不在time/duration
包装上。
TA贡献1873条经验 获得超9个赞
在大多数情况下,按照 Dave Cheney 的建议来定义调用者的接口将避免循环依赖。但这只会解决平面数据模型。在您的情况下,您有嵌套实体,即 HyperVisor 具有返回 MounthPath 的功能。我们可以通过两种方式对此进行建模
在单独的包中定义 MouthPath(如您建议的那样)。此外,从长远来看,在 virtualbox 包中定义接口将有助于为 Hypervisor 提供替代实现。
让 virtualbox 将 Hypervisor 和 MounthPath 都定义为接口。一个缺点是管理程序实现包使用 virtualbox.MouthPath 接口来满足如下传递时的接口。
//hypervisor/hypervisor.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
}
并有另一个包(不需要嵌套)
//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
// ....
}
- 2 回答
- 0 关注
- 151 浏览
添加回答
举报