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

Hun*_*ham -1 inheritance design-patterns composition go

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

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

第一个例子

type BaseClass struct {
   db *DB
}

func NewBaseClass(db *DB) *BaseClass {
  return &BaseClass{db}
}

type ChildrenClass1 struct {
     baseClass *BaseClass
}

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

type ChildrenClass2 struct {
     baseClass *BaseClass
}

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

func main(){
  db := NewDB()
  chilrend1 := NewChildrenClass1(db)
  chilrend2 := NewChildrenClass2(db)
}
Run Code Online (Sandbox Code Playgroud)

第二个例子

type BaseClass struct {
   db *DB
}

func NewBaseClass(db *DB) *BaseClass {
  return &BaseClass{db}
}

type ChildrenClass1 struct {
     baseClass *BaseClass
}

func NewChildrenClass1(baseClass *BaseClass) *ChildrenClass1 {
  return &ChildrenClass1{baseClass}
}

type ChildrenClass2 struct {
     baseClass *BaseClass
}

func NewChildrenClass2(baseClass *BaseClass) *ChildrenClass2 {
  return &ChildrenClass2{baseClass}
}

func main(){
  db := NewDB()
  baseClass := NewBaseClass(db)
  chilrend1 := NewChildrenClass1(baseClass)
  chilrend2 := NewChildrenClass2(baseClass)
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*hls 6

在 Go 中,您可能找不到定义组合或聚合的正确方法,而您可能会在许多其他基于 OOP 的语言中找到这种方法。这只是因为Go 没有类、没有对象、没有异常、没有模板。

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

话虽如此,让我们看看一些常见的定义,看看我们能做什么:

组合意味着子级不能独立于父级而存在的关系。示例:House(父母)和Room(孩子)。房间并不独立于房屋[ 1 ]而存在。

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

因此,在聚合和组合中,“实例”“拥有”另一种类型的对象。但有一个微妙的区别:聚合意味着子级可以独立于父级而存在的关系。组合意味着子级不能独立于父级而存在的关系。

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

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

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

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

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

第一个例子重写

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 &Room{l}
}

type House1 struct {
    Room *Room
}

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

type House2 struct {
    Room *Room
}

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

func main(){
  lamps := []Lamp{}
  house1 := NewHouse1(&lamps)
  house2 := NewHouse2(&lamps)
}
Run Code Online (Sandbox Code Playgroud)

重写的第二个例子:

package main

type LibraryCard struct {}

type Student struct {
   LibCard *LibraryCard
}

func NewStudent(l *LibraryCard) *Student {
  return &Student{l}
}

type Classroom1 struct {
    Student *Student
}

func NewClassroom1(s *Student) *Classroom1 {
  return &Classroom1{s}
}

type Classroom2 struct {
    Student *Student
}

func NewClassroom2(s *Student) *Classroom2 {
  return &Classroom2{s}
}

func main(){
  lc := new(LibraryCard)
  student := NewStudent(lc)
  classroom1 := NewClassroom1(student)
  classroom2 := NewClassroom2(student)
}
Run Code Online (Sandbox Code Playgroud)