在 Golang 中使用组合的正确方法是啥

Posted

技术标签:

【中文标题】在 Golang 中使用组合的正确方法是啥【英文标题】:What is the proper way using composition in Golang在 Golang 中使用组合的正确方法是什么 【发布时间】:2022-01-02 17:23:26 【问题描述】:

我是 OOP 人,最近我必须在 Golang 上工作,这是我以前没有做过的语言。虽然我已经阅读了很多关于组合的文章,但我注意到在 Golang 上正确使用它有点棘手

假设我有两个 Golang 组合的例子,我不知道哪个是正确的,它们之间会有所不同吗?谢谢

第一个例子

type BaseClass struct 
   db *DB


func NewBaseClass(db *DB) *BaseClass 
  return &BaseClassdb


type ChildrenClass1 struct 
     baseClass *BaseClass


func NewChildrenClass1(db *DB) *ChildrenClass1 
  baseClass := NewBaseClass(db)
  return &ChildrenClass1baseClass


type ChildrenClass2 struct 
     baseClass *BaseClass


func NewChildrenClass2(db *DB) *ChildrenClass2 
  baseClass := NewBaseClass(db)
  return &ChildrenClass2baseClass


func main()
  db := NewDB()
  chilrend1 := NewChildrenClass1(db)
  chilrend2 := NewChildrenClass2(db)

第二个例子

type BaseClass struct 
   db *DB


func NewBaseClass(db *DB) *BaseClass 
  return &BaseClassdb


type ChildrenClass1 struct 
     baseClass *BaseClass


func NewChildrenClass1(baseClass *BaseClass) *ChildrenClass1 
  return &ChildrenClass1baseClass


type ChildrenClass2 struct 
     baseClass *BaseClass


func NewChildrenClass2(baseClass *BaseClass) *ChildrenClass2 
  return &ChildrenClass2baseClass


func main()
  db := NewDB()
  baseClass := NewBaseClass(db)
  chilrend1 := NewChildrenClass1(baseClass)
  chilrend2 := NewChildrenClass2(baseClass)

【问题讨论】:

您尝试对 Go 中绝对不可能的继承建模。不管你怎么努力。不管你多么聪明。无论你多么喜欢作曲。现在和永远忘记 Go 中的 Base 和 Child 的东西,它不起作用。 任何时候你称任何东西为“基础”、“子”或“类”,你的开端就很糟糕。 Go 中不存在这些概念,并且组合没有层次结构,因此任何正确使用组合都不会有“基”或“子”。这些概念存在于继承模型中。 嘿,有人在这里问了同样的问题:***.com/questions/61073683/… -- 这个答案对你有帮助吗? 【参考方案1】:

在 Go 中,您可能找不到像在许多其他基于 OOP 的语言中那样定义组合或聚合的正确方法。这只是因为Go has no classes,没有对象,没有异常,也没有模板。

但是 Go 有结构体。结构是用户定义的类型。结构类型(带有方法)的用途与其他语言中的类类似。

说了这么多,让我们看看一些常见的定义,看看我们能做什么:

Composition 意味着子级不能独立于父级而存在的关系。示例:房屋(父)和房间(子)。房间不存在独立于房屋[1]。

聚合,另一方面,意味着孩子可以独立于父母而存在的关系。示例:教室(家长)和学生(孩子)。删除教室,学生还在[1]。

因此,在aggregation and composition 中,“实例”“拥有”另一个类型的对象。但是有一个细微的区别:聚合意味着子级可以独立于父级而存在的关系。 Composition 意味着孩子不能独立于父母而存在的关系。

到目前为止,这就是我们现在从composition 了解到的:

没有父母,孩子就无法生存 组合是指将更简单的类型组合成更复杂的类型 当然,我们主要使用它来重用代码

回答您的问题: 两者看起来都正确,但是,

第一个示例更接近于组合,因为没有父级,子级就不会存在; 第二个示例更像是一个聚合,因为如果您删除父级,子级将保持存在。

我重写了你的代码,试图举例说明:

重写第一个示例

package main

//Lamp struct is here to suppress the *DB that was in the original example
type Lamp struct 

type Room struct 
    Lamps *[]Lamp



func NewRoom(l *[]Lamp) *Room 
  return &Rooml


type House1 struct 
    Room *Room


func NewHouse1(l *[]Lamp) *House1 
  r := NewRoom(l)
  return &House1r


type House2 struct 
    Room *Room


func NewHouse2(l *[]Lamp) *House2 
  r := NewRoom(l)
  return &House2r


func main()
  lamps := []Lamp
  house1 := NewHouse1(&lamps)
  house2 := NewHouse2(&lamps)

重写的第二个示例:

package main

type LibraryCard struct 

type Student struct 
   LibCard *LibraryCard


func NewStudent(l *LibraryCard) *Student 
  return &Studentl


type Clas-s-room1 struct 
    Student *Student


func NewClas-s-room1(s *Student) *Clas-s-room1 
  return &Clas-s-room1s


type Clas-s-room2 struct 
    Student *Student


func NewClas-s-room2(s *Student) *Clas-s-room2 
  return &Clas-s-room2s


func main()
  lc := new(LibraryCard)
  student := NewStudent(lc)
  clas-s-room1 := NewClas-s-room1(student)
  clas-s-room2 := NewClas-s-room2(student)

【讨论】:

感谢@marcel-kohls,讲解的很详细

以上是关于在 Golang 中使用组合的正确方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

为组合类创建 DAO 类的正确方法是啥

使用通用虚函数实现的任意组合实现派生类的正确方法是啥?

组合大量表和字段的正确方法是啥?

检测图像中矩形的最简单*正确*方法是啥?

在 golang 中使用私有地图、切片的最佳实践是啥?

如何减少 golang tcp 服务器中的 cpu 使用率?