Part27: Go的面向對象 - 組合代替繼承

歡迎繼續Golang系列教程第27節


Go並不支持繼承,但是它支持組合。組合的通用定義是 “放到一起”。組合的一個例子是 汽車,汽車由車輪,引擎和各種其他部件組成。

通過嵌入結構體組合

在 Go 中,組合可以通過將一個結構體類型嵌入另一個來獲得。

博客文章是組合的一個完美例子。每個博客文章都有一個標題,內容和作者信息。這可以通過使用組合完美地表示。在文章的下一步,我們將學習這些是如何完成的。

我們首先創建 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)
}

在上面的代碼片段,我們創建一個有 firstnamelastNamebio 字段的結構體 author。我們也使用 author 作爲接收器類型添加一個方法 fullName(),該方法返回一個作者的全名字。

下一步將創建一個 post 結構體。

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 結構體有字段 titlecontent。它還有一個嵌入的匿名字段 author。這個字段表示 post結構體由 author組合而成。現在 post 結構體可以訪問 author 結構體的所有字段和方法。我們還爲 post 結構體添加 details() 方法,它將打印標題,內容和作者的命名和個人簡歷。

當一個結構體字段嵌入的是另一個結構體,Go 給我們提供了訪問嵌入字段的選項,就好比他們是外部結構體的一部分一樣。這意味着上面代碼第 11 行的 p.author.fullName() 可以使用 p.fullName() 代替。因此 details() 方法可以像下面一樣重寫。

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

現在我們已經準備了 authorpost 結構體。我們創建一個博客文章來完成這個程序

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()
}

上面程序的主函數在第 31 行創建一個新的作者。在第 36 行通過嵌入 author1 創建一個新的博客文章 。這個程序打印

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

嵌入結構體切片

我們要以繼續這個例子,使用博客文章切片 創建一個 web 站點。

我們首先定義 website 結構體。在上面已有的程序主函數添加下列代碼並運行它。

type website struct {  
        []post
}
func (w website) contents() {  
    fmt.Println("Contents of Website\n")
    for _, v := range w.posts {
        v.details()
        fmt.Println()
    }
}

當在添加完上面代碼後運行程序,編譯器將報如下錯誤:

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

這個錯誤指向嵌入的結構體切片 []post。原因是不能匿名嵌入一個切片。需要一個字段名。所以我們來修復該錯誤

type website struct {  
        posts []post
}

向 post 切片 []post 添加字段名 posts

現在修改主函數,爲 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\n")
    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()
}

在上面的主函數中,我們創建一個作者 author1 和三個貼子 post1post2post3。最後我們在第 62 行通過嵌入這三個貼子創建一個站點 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  

**下一教程 - 多態 **

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章