Композиция вместо наследования Go

Go не поддерживает наследование, но поддерживает композицию. Общее определение композиции - «собрать вместе». Одним из примеров композиции является автомобиль. Автомобиль состоит из колес, двигателя и различных других частей.

Композиция путем встраивания структур

Композиция может быть достигнута в Go is путем встраивания одного типа структуры в другой.


Пост в блоге — прекрасный пример композиции. Каждый пост в блоге имеет заголовок, содержание и информацию об авторе. Это может быть прекрасно представлено с помощью композиции. В следующих шагах этого урока мы узнаем, как это делается.


Давайте сначала создадим 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() с author типом получателя as, который возвращает полное имя автора.


Следующим шагом будет создание blogPost структуры.

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 имеет поля title, content. Он также имеет встроенное анонимное поле author. Это поле означает, что blogPostструктура состоит из author. Теперь blogPostструктура имеет доступ ко всем полям и методам структуры author.


Мы также добавили details() в структуру метод blogPost, который печатает заголовок, контент, полное имя и биографию автора.


Всякий раз, когда одно поле структуры встраивается в другое, Go дает нам возможность доступа к встроенным полям, как если бы они были частью внешней структуры. Это означает, что p.author.fullName() в строке №. 11 приведенного выше кода можно заменить на p.fullName().


Следовательно, details()метод можно переписать следующим образом:

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

Теперь, когда у нас есть готовые структуры author и blogPost, давайте закончим эту программу, создав запись в блоге.

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. Эта программа печатает:

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

Встраивание среза структур

Мы можем сделать еще один шаг в этом примере и создать веб-сайт.


Сначала определим website структуру. Добавьте следующий код над основной функцией существующей программы и запустите ее.

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

Когда вы запускаете указанную выше программу после добавления вышеуказанного кода, компилятор выдает следующую ошибку:

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

Эта ошибка указывает на встроенный фрагмент структур []blogPost. Причина в том, что невозможно анонимно встроить фрагмент. Необходимо указать имя поля. Итак, давайте исправим эту ошибку и порадуем компилятор.

type website struct {  
        blogPosts []blogPost
}

Добавили поле blogPosts, которое является срезом []blogPosts.


Теперь давайте изменим основную функцию и создадим несколько постов для нашего нового сайта.

Полная программа после изменения основной функции представлена ​​ниже:

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

В основной функции выше мы создали автора author1и три сообщения post1, post2а также post3. Наконец, мы создали веб-сайт wв строке №. 62, внедрив эти 3 поста и отобразив содержимое в следующей строке.


Эта программа выведет:

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

Это подводит нас к концу этого урока. Спасибо за прочтение.