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

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

В приведенном выше фрагменте кода мы создали author структуру с полями firstName , lastName и bio . Мы также добавили метод fullName() с типом author, который возвращает полное имя автора.

Следующим шагом будет создание 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() приведенного выше кода можно заменить на 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()
}

Main функция программы выше создает нового автора author1 := author{}. Создается новый пост blogPost1 := blogPost{} путем встраивания 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

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