为什么您想在golang中使用组合?

16

在以下代码中,我展示了我认为在golang中嵌入(方法被提升)和组合(方法不被提升)之间的区别。

为什么你会想要在golang中使用组合?

type obj1Inherited struct {
    obj2
}

type obj1Composed struct {
    someobj obj2
}

type obj2 struct {
}

func (o obj2) printTest() {
    fmt.Println("obj2")
}

func main() {
    o := obj1Inherited{}
    o.printTest() //fine - printTest is promoted

    obj1Composed := obj1Composed{}
    obj1Composed.someobj.printTest() //fine because I'm using the composed obj
    obj1Composed.printTest() //not fine - printTest is NOT promoted

7
有人可以解释一下为什么这个被踩了吗?我在SO上用三种不同的方式提出了同样的问题,每次都没有得到答案,也没有有帮助的评论。 - Charlie
4个回答

17

值得仔细阅读Effective Go中关于嵌入的部分。

一个常见的例子是在结构体/映射中添加Mutex。

type SafeStruct struct {
    SomeField string 
    *sync.Mutex
}

打字会更容易

safe := SafeStruct{SomeField: "init value"}

safe.Lock()
defer safe.Unlock()
safe.SomeField = "new value"

与其编写重复的适当包装函数,或者让代码笨拙不堪,

safe.mutex.Unlock()

当您唯一需要使用互斥锁字段的是访问方法(在这种情况下为Lock()Unlock())时

当您尝试在嵌入字段上使用多个函数(实现类似io.ReadWriter的接口)时,这将变得更加有用。


1
也值得一提的是-我在Stack Overflow上看到过更为成熟的语言中更加“愚蠢”的问题,而这些问题仍然得到了回答并且没有被大量地踩。这给我留下了深刻印象,即Go社区不愿意帮助新手。 - Charlie
@Charlie,很抱歉你有这样的感受。我并不认为你的问题是“愚蠢”的或者值得被downvote。SO Go社区似乎与Golang论坛、Slack频道或Go-Nuts邮件列表不同。在那里,关于为什么/风格的问题可能会得到更好的回答。希望我的回答对你有所帮助。 - matt.s
感谢指出互斥锁的情况 - 这很有道理,但似乎是边缘情况。至于像io.ReadWriter这样的东西,我认为最佳实践应该是“装饰”,在这种情况下,您将希望提升方法,以便您可以调用类似o.save()的东西,然后使用类似io.Write()的东西来实现它。对此有何想法?https://www.javacodegeeks.com/2014/09/oop-alternative-to-utility-classes.html - Charlie
我不得不为一个被多个goroutine访问的map使用mutex。嵌入并不经常使用,但像在bufio.ReadWriter中一样非常方便。 - matt.s
1
@Charlie 嵌套是一个有用的组合包装器。组合是将较小部分的功能/字段包含在较大部分中,而不是通过与另一个类/对象的关系获取功能/字段的继承。 - matt.s
显示剩余5条评论

0

我会尝试回答原始问题 - 有时人们使用“组合”而不是嵌入来隐藏嵌入结构的功能。这不是很好的用例 - 但有时人们更喜欢它。

type Obj1composed struct {
  notExportedObj1 obj1
}

func NewObj1Composed(someParam Params) Obj1composed {
...
}

func (o Obj1Composed) Print() {
  // Some heavy calculations here. Make Dozens of API calls
  // print some data
}

0

0

我想再提一点,关于你的例子中第一个情况。

如果obj1Inheritedobj2有同名方法,那么从obj1Inherited实例调用该方法时,将始终执行obj1Inherited方法。

要调用obj2方法,可以使用不进行提升的另一种方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接