为了账号安全,请及时绑定邮箱和手机立即绑定

当有接口及其在不同包中的实现时如何管理循环依赖

当有接口及其在不同包中的实现时如何管理循环依赖

Go
幕布斯6054654 2022-07-11 17:35:41
我的项目结构如下所示:代码结构:hypervisor├── hypervisor.go├── hyperv│   └── hyperv.go└── virtualbox    ├── vbox.go    └── vboxprops.go源代码://hypervisor/hypervisor.gopackage hypervisortype 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并有另一个(嵌套)包://hypervisor/virtualbox/vbox.gopackage virtualboxtype 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正如所见,当然,这样的代码会导致import cycle not allowed . 因为:hypervisorpcakge 引用virtualbox.VirtualBox类型virtualbox包引用hypervisor.MountPath类型我知道如果我将结构移动MounthPath到另一个包会解决问题,但我认为这不是正确的解决方案设计方式。有什么建议吗?
查看完整描述

2 回答

?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

例如,我会做的一种最简单的方法是将实体分成entities包(在这种情况下:HypervisorVirtualbox结构是实体或任何你想调用的东西)。
这是我认为最常见的设计,因此内部包使用的每个结构都不会导致循环依赖。
使用示例:所有time包结构都在顶级包级别。time.Time{},time.Duration{}time.Duration不在time/duration包装上。

查看完整回答
反对 回复 2022-07-11
?
眼眸繁星

TA贡献1873条经验 获得超9个赞

在大多数情况下,按照 Dave Cheney 的建议来定义调用者的接口将避免循环依赖。但这只会解决平面数据模型。在您的情况下,您有嵌套实体,即 HyperVisor 具有返回 MounthPath 的功能。我们可以通过两种方式对此进行建模

  1. 在单独的包中定义 MouthPath(如您建议的那样)。此外,从长远来看,在 virtualbox 包中定义接口将有助于为 Hypervisor 提供替代实现。

  2. 让 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

    // ....


查看完整回答
反对 回复 2022-07-11
  • 2 回答
  • 0 关注
  • 151 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信