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