Menu
Coddy logo textTech

Затенение встроенных методов

Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 39 из 107.

Иногда нужно, чтобы внешняя структура предоставляла собственную реализацию метода, который уже есть у встроенного типа. Это называется затенением и позволяет переопределять продвигаемые методы с помощью пользовательского поведения.

Когда вы определяете method во внешней структуре с тем же именем, что и embedded method, внешний method имеет приоритет:

type Animal struct {
    Name string
}

func (a Animal) Speak() string {
    return "Some sound"
}

type Dog struct {
    Animal
    Breed string
}

func (d Dog) Speak() string {
    return "Woof!"
}

Теперь, когда вы вызываете Speak() для Dog, используется внешний метод:

func main() {
    d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
    
    fmt.Println(d.Speak())        // Woof! - метод Dog
    fmt.Println(d.Animal.Speak()) // Какой-то звук - метод Animal
}

embedded метод не исчез. Ты всё ещё можешь явно получить к нему доступ через имя embedded типа. Этот шаблон полезен, когда ты хочешь настроить поведение, сохранив доступной исходную реализацию, например чтобы вызвать её из переопределяющего метода:

func (d Dog) Speak() string {
    return d.Animal.Speak() + " (but actually Woof!)"
}

Скрытие позволяет контролировать, какое поведение предоставляется, сохраняя доступ к исходному через явную квалификацию.

challenge icon

Задание

Легко

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

Вы организуете код в трёх файлах:

  • base.go: Создайте структуру BaseNotification с полями Title и Priority (both строкового типа). Добавьте ей метод Format() string, который возвращает notification в стандартном формате: [Priority] Title.
  • channels.go: Создайте два типа каналов уведомлений, которые встраивают BaseNotification и затеняют метод Format собственными реализациями:
    • EmailNotification с полем Recipient. Его метод Format() должен возвращать Email to [Recipient]: [Priority] Title
    • SlackNotification с полем Channel. Его метод Format() должен вызывать встроенный метод BaseNotification.Format() и добавлять #[Channel]: в начало результата
  • main.go: Считайте сведения об уведомлении из входных данных, создайте оба типа уведомлений и продемонстрируйте затенение, выведя:
    1. отформатированный output EmailNotification (с использованием его затенённого метода)
    2. базовый формат EmailNotification (явно вызывая встроенный метод)
    3. отформатированный output SlackNotification (который внутри использует базовый метод)

Будут предоставлены следующие входные данные:

  • Строка 1: Заголовок notification
  • Строка 2: Уровень priority
  • Строка 3: Получатель email
  • Строка 4: Имя канала Slack

Например, если заданы Server Alert, HIGH, admin@company.com и ops-alerts, output должен быть таким:

Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server Alert

Обратите внимание, как EmailNotification полностью заменяет базовое форматирование, тогда как SlackNotification расширяет его, вызывая исходный метод и добавляя контекст канала. Оба подхода демонстрируют разные способы эффективного использования затенения методов.

Попробуйте сами

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// Читать заголовок уведомления
	scanner.Scan()
	title := scanner.Text()
	
	// Читать уровень приоритета
	scanner.Scan()
	priority := scanner.Text()
	
	// Читать получателя email
	scanner.Scan()
	recipient := scanner.Text()
	
	// Читать имя канала Slack
	scanner.Scan()
	channel := scanner.Text()
	
	// TODO: Создать EmailNotification с базовым уведомлением, title, priority и recipient
	
	// TODO: Создать SlackNotification с базовым уведомлением, title, priority и channel
	
	// TODO: Вывести форматированный вывод EmailNotification (используя его затенённый метод)
	
	// TODO: Вывести базовый формат EmailNotification (явно вызывая встроенный метод)
	
	// TODO: Вывести форматированный вывод SlackNotification
	
	fmt.Println() // Заглушка - удалить при реализации
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Go