组合 vs 继承
Golang不支持继承,但支持组合。怎么理解组合呢?可以拿车来举例,车就是一个轮子、发动机等组件的一个组合。这个模式跟现在流行的前端开发模式有点像,比如React组件化,也是推崇组合,摒弃继承。
实现组合:结构体嵌套
Golang中可以通过结构体嵌套来实现组合。我们拿博客来举个例子,一篇博客包含标题、内容以及作者等信息,这三部分组合在一起形成一篇博客。 我们首先创建一个结构体类型author
用来表示作者。
package main
import "fmt"
type author struct {
firstName string
lastName string
bio string
}
func (a author) fullName() string {
return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}
这里我们首先创建了一个结构体类型author
,该结构体类型包含三个属性firstName
、lastName
以及bio
。然后我们给该结构体类型绑定了一个方法fullName
用来获取姓名全称。
下面我们来创建博客结构体类型post
,并绑定一个方法details
。
type post struct {
title string
content string
author
}
func (p post) details() {
fmt.Println("Title: ", p.title)
fmt.Println("Content: ", p.content)
fmt.Println("Author: ", p.author.fullName())
fmt.Println("Bio: ", p.author.bio)
}
这里的结构体类型post
包含title
、content
两个属性,还包含一个匿名嵌套属性author
。这里包含了一个嵌套结构体author
,因此我们说author
是post
的一个组成部分,或者说post
由author
组成。这时我们可以通过post
来访问author
的各个属性和方法。 在details
方法中我们通过结构体类型post
来访问了title
、content
属性字段以及author
属性的fullName
方法和bio
属性。
对于匿名嵌套属性,我们可以简写如下,将匿名字段略去:
func (p post) details() {
fmt.Println("Title: ", p.title)
fmt.Println("Content: ", p.content)
fmt.Println("Author: ", p.fullName())
fmt.Println("Bio: ", p.bio)
}
到这里我们已经定义好了两个结构体类型及其绑定的方法:author
和post
,下面写个测试程序来测试下:
package main
import "fmt"
type author struct {
firstName string
lastName string
bio string
}
func (a author) fullName() string {
return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}
type post struct {
title string
content string
author
}
func (p post) details() {
fmt.Println("Title: ", p.title)
fmt.Println("Content: ", p.content)
fmt.Println("Author: ", p.fullName())
fmt.Println("Bio: ", p.bio)
}
func main() {
author1 := author{
"Naveen",
"Ramanathan",
"Golang Enthusiast",
}
post1 := post{
"Inheritance in Go",
"Go supports composition instead of inheritance",
author1,
}
post1.details()
}
该程序输出如下:
Title: Inheritance in Go
Content: Go supports composition instead of inheritance
Author: Naveen Ramanathan
Bio: Golang Enthusiast
嵌套结构体切片
前面我们看到,一个post
可以由title
、content
和author
组成,这三个属性都是单个的。但是一个网站(website)肯定是包含多条博客(post
)的,因此我们可以在website
结构体类型下面掐套一个post
结构体切片:
type website struct {
posts []post
}
func (w website) contents() {
fmt.Println("Contents of website")
for _, v := range w.posts {
v.details()
fmt.Println()
}
}
这里我们在结构体website
内部嵌套的是切片类型[]post
。我们再升级下main
函数来创建多个post
结构体变量,并创建一个website
结构体变量:
package main
import "fmt"
type author struct {
firstName string
lastName string
bio string
}
func (a author) fullName() string {
return fmt.Sprintf("%s %s", a.firstName, a.lastName)
}
type post struct {
title string
content string
author
}
func (p post) details() {
fmt.Println("Title: ", p.title)
fmt.Println("Content: ", p.content)
fmt.Println("Author: ", p.fullName())
fmt.Println("Bio: ", p.bio)
}
type website struct {
posts []post
}
func (w website) contents() {
fmt.Println("Contents of website")
for _, v := range w.posts {
v.details()
fmt.Println()
}
}
func main() {
author1 := author{
"Naveen",
"Ramanathan",
"Golang Enthusiast",
}
post1 := post{
"Inheritance in Go",
"Go supports composition instead of inheritance",
author1,
}
post2 := post{
"Struct instead of Classes in Go",
"Go does not support classes but methods can be added to structs",
author1,
}
post3 := post{
"Concurrency",
"Go is a concurrent language and not a parallel one",
author1,
}
w := website{
posts: []post{post1, post2, post3},
}
w.contents()
}
这里我们创建了三个结构体post
类型的变量post1
,post2
,post3
,然后构建了一个切片内嵌到了结构体变量w
内。
该程序输出如下:
Contents of website
Title: Inheritance in Go
Content: Go supports composition instead of inheritance
Author: Naveen Ramanathan
Bio: Golang Enthusiast
Title: Struct instead of Classes in Go
Content: Go does not support classes but methods can be added to structs
Author: Naveen Ramanathan
Bio: Golang Enthusiast
Title: Concurrency
Content: Go is a concurrent language and not a parallel one
Author: Naveen Ramanathan
Bio: Golang Enthusiast
Last updated
Was this helpful?