Композиция вместо наследования 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
Это подводит нас к концу этого урока. Спасибо за прочтение.