用组合代替继承
Q7nl1s admin

Go不支持继承,但它支持组合。组合的一般定义是 “组合在一起”。组成的一个例子是一辆汽车。一辆汽车是由车轮、发动机和其他各种部件组成的。

通过嵌入结构进行组合

Go中可以通过将一个结构类型嵌入另一个结构类型来实现组合。

博客文章就是一个完美的组合例子。每篇博文都有一个标题、内容和作者信息。这可以用组合来完美地表示。在本教程的下一步骤中,我们将学习如何实现这一目标。

首先,让我们创建 author 结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 结构,其字段为firstNamelastNamebio。我们还添加了一个方法fullName(),将author作为接收方类型,该方法返回author的全名。

下一步将是创建blogPost结构。

1
2
3
4
5
6
7
8
9
10
11
12
type blogPost struct {  
title string
content string
author
}

func (b blogPost) details() {
fmt.Println("Title: ", b.title)
fmt.Println("Content: ", b.content)
fmt.Println("Author: ", b.author.fullName())
fmt.Println("Bio: ", b.author.bio)
}

blogPost结构有titlecontent等字段。它也有一个嵌入式匿名字段author。这个字段表示blogPost结构是由author组成的。现在blogPost结构可以访问author结构的所有字段和方法。我们还为blogPost结构添加了details()方法,可以打印出作者的标题、内容、全名和简历。

每当一个结构字段嵌入到另一个结构中时,Go 都会让我们选择访问嵌入的字段,就像它们是外部结构的一部分一样。这意味着上述代码第11行中的b.author.fullName()可以替换为b.fullName()。因此,details()方法可以重写如下。

1
2
3
4
5
6
func (b blogPost) details() {  
fmt.Println("Title: ", b.title)
fmt.Println("Content: ", b.content)
fmt.Println("Author: ", b.fullName())
fmt.Println("Bio: ", b.bio)
}

现在我们已经准备好了authorblogPost结构,让我们通过创建一篇博文来完成这个程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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 blogPost struct {
title string
content string
author
}

func (b blogPost) details() {
fmt.Println("Title: ", b.title)
fmt.Println("Content: ", b.content)
fmt.Println("Author: ", b.fullName())
fmt.Println("Bio: ", b.bio)
}

func main() {
author1 := author{
"Naveen",
"Ramanathan",
"Golang Enthusiast",
}
blogPost1 := blogPost{
"Inheritance in Go",
"Go supports composition instead of inheritance",
author1,
}
blogPost1.details()
}

上述程序的主要功能是在第31行创建一个新的作者。在第36行创建了一个新的帖子,嵌入author1。这个程序会打印:

1
2
3
4
Title:  Inheritance in Go  
Content: Go supports composition instead of inheritance
Author: Naveen Ramanathan
Bio: Golang Enthusiast

嵌入结构的片断

我们可以在这个例子的基础上更进一步,用博客文章的切片来创建一个网站:)。

我们先来定义website结构。请在现有程序的main函数上方添加以下代码并运行。

1
2
3
4
5
6
7
8
9
10
type website struct {  
[]blogPost
}
func (w website) contents() {
fmt.Println("Contents of Website\n")
for _, v := range w.blogPosts {
v.details()
fmt.Println()
}
}

在添加上述代码后运行上述程序时,编译器会报如下错误:

1
main.go:31:9: syntax error: unexpected [, expecting field name or embedded type  

这个错误指向结构[]blogPost的嵌入式切片。原因是不可能匿名地嵌入一个片断。需要一个字段名。因此,让我们来修复这个错误,让编译器满意。

1
2
3
type website struct {  
blogPosts []blogPost
}

我已经添加了blogPosts字段,它是一个[]blogPosts切片。

现在让我们修改main函数,为我们的新网站创建几个帖子。

修改主函数后的完整程序提供如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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 blogPost struct {
title string
content string
author
}

func (p blogPost) details() {
fmt.Println("Title: ", p.title)
fmt.Println("Content: ", p.content)
fmt.Println("Author: ", p.fullName())
fmt.Println("Bio: ", p.bio)
}

type website struct {
blogPosts []blogPost
}

func (w website) contents() {
fmt.Println("Contents of Website\n")
for _, v := range w.blogPosts {
v.details()
fmt.Println()
}
}

func main() {
author1 := author{
"Naveen",
"Ramanathan",
"Golang Enthusiast",
}
blogPost1 := blogPost{
"Inheritance in Go",
"Go supports composition instead of inheritance",
author1,
}
blogPost2 := blogPost{
"Struct instead of Classes in Go",
"Go does not support classes but methods can be added to structs",
author1,
}
blogPost3 := blogPost{
"Concurrency",
"Go is a concurrent language and not a parallel one",
author1,
}
w := website{
blogPosts: []blogPost{blogPost1, blogPost2, blogPost3},
}
w.contents()
}

在上面的main函数中,我们创建了一个author author1和三个posts post1post2post3。最后,我们在第63行通过嵌入这3个posts创建了一个网站w,并在下一行显示其内容。

这个程序将输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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

至此,本教程结束。祝你有个愉快的一天。

 Comments
Comment plugin failed to load
Loading comment plugin
Powered by Hexo & Theme Keep
Unique Visitor Page View