[英]How do I have a golang interface implementation return implementation of another interface?
[英]How to manage cyclic dependencies when have interface and its implementation in different packages
我的項目結構如下所示:
代碼結構:
hypervisor
├── hypervisor.go
├── hyperv
│ └── hyperv.go
└── virtualbox
├── vbox.go
└── vboxprops.go
源代碼:
//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
並有另一個(嵌套)包:
//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
正如所見,當然,此類代碼會導致import cycle not allowed
。 因為:
hypervisor
pcakge 引用virtualbox.VirtualBox
類型hypervisor.MountPath
類型的virtualbox
包我知道如果我將 struct MounthPath
移動到另一個包會解決這個問題,但我認為這不是正確的解決方案設計。
有什么建議嗎?
我會做的最簡單的方法之一是將實體分離到entities
包中(在這種情況下: Hypervisor
和Virtualbox
結構是實體或任何你想稱呼它的東西)。
這是我認為最常見的設計,因此內部包使用的每個結構都不會導致循環 deps。
用法示例:所有time
包結構都在頂級包級別。 time.Time{}
、 time.Duration{}
等time.Duration
不屬於time/duration
包。
在大多數情況下,遵循 Dave Cheney 的建議由調用者定義接口將避免循環依賴。 但這只能解決平面數據模型。 在您的情況下,您有嵌套實體,即 HyperVisor 具有返回 MounthPath 的功能。 我們可以通過兩種方式對此進行建模
在單獨的包中定義 MouthPath(如您所建議的)。 此外,在 virtualbox 包中定義接口將有助於為 Hypervisor 提供替代實現。
讓 virtualbox 將 Hypervisor 和 MounthPath 定義為接口。 一個缺點是管理程序實現包使用 virtualbox.MouthPath 接口來滿足如下傳遞時的接口。
//管理程序/管理程序.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
// ....
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.