Menu
Coddy logo textTech

Неявная реализация

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

Во многих объектно-ориентированных языках, таких как Java или C#, необходимо явно объявить, что тип реализует интерфейс, используя такие ключевые слова, как implements. Go использует другой подход: реализация интерфейса является неявной.

Тип удовлетворяет интерфейсу, просто реализуя все его method. Нет необходимости где-либо объявлять эту связь. Компилятор выясняет это automatically.

type Writer interface {
    Write(data string) int
}

type FileWriter struct {
    Filename string
}

// FileWriter неявно реализует Writer
func (f FileWriter) Write(data string) int {
    fmt.Println("Writing to", f.Filename)
    return len(data)
}

Обратите внимание: в FileWriter нет объявления implements Writer. Поскольку в FileWriter есть метод Write(data string) int, соответствующий сигнатуре интерфейса, он автоматически удовлетворяет интерфейсу Writer.

У этого проектного решения есть важное следствие: вы можете определять интерфейсы уже после того, как типы существуют. Если в сторонней библиотеке есть тип с нужными вам методами, вы можете создать интерфейс, которому этот тип уже соответствует, не изменяя исходный код.

func Save(w Writer, content string) {
    w.Write(content)
}

func main() {
    fw := FileWriter{Filename: "data.txt"}
    Save(fw, "Hello!")  // Работает, потому что FileWriter удовлетворяет Writer
}

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

challenge icon

Задание

Легко

Давайте создадим систему доставки сообщений, которая демонстрирует, как типы неявно удовлетворяют интерфейсам в Go. Вы создадите разные типы messenger, которые все удовлетворяют одному и тому же интерфейсу, не объявляя явно об этой связи.

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

  • messengers.go: Define интерфейс Messenger с одним методом Send(message string) string. Затем создайте две структуры, которые будут неявно удовлетворять этому интерфейсу:
    • EmailMessenger с полем Address (строка)
    • SMSMessenger с полем PhoneNumber (строка)
    У каждой структуры должен быть метод Send, возвращающий строку с описанием доставки. Ни одна из структур не должна явно объявлять, что она реализует Messenger: Go автоматически определит это на основе сигнатур методов.
  • main.go: Создайте function с именем DeliverMessage, которая принимает любой Messenger и строку message, а затем возвращает результат вызова Send. Считайте контактную информацию из ввода, создайте оба типа messenger и используйте свою function для доставки сообщений через каждый из них.

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

  • Строка 1: Email address
  • Строка 2: Phone number
  • Строка 3: Message to send

Ваши методы Send должны возвращать строки в следующих форматах:

  • EmailMessenger: Email to [Address]: [message]
  • SMSMessenger: SMS to [PhoneNumber]: [message]

Например, если заданы alice@example.com, 555-1234 и Hello!, результатом должен быть:

Email to alice@example.com: Hello!
SMS to 555-1234: Hello!

Главная идея заключается в том, что ваша DeliverMessage function принимает любой Messenger, а и EmailMessenger, и SMSMessenger удовлетворяют этому интерфейсу просто благодаря наличию соответствующего метода Send. Ключевого слова implements нет нигде: неявная реализация в Go делает всё необходимое.

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

package main

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

// TODO: Создайте функцию DeliverMessage, которая принимает любой Messenger
// и строку сообщения, затем возвращает результат вызова Send

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Read email address
	email, _ := reader.ReadString('\n')
	email = email[:len(email)-1]
	
	// Прочитать номер телефона
	phone, _ := reader.ReadString('\n')
	phone = phone[:len(phone)-1]
	
	// Прочитать сообщение
	message, _ := reader.ReadString('\n')
	if len(message) > 0 && message[len(message)-1] == '\n' {
		message = message[:len(message)-1]
	}
	
	// TODO: Создайте EmailMessenger с адресом электронной почты
	
	// TODO: Создайте SMSMessenger с номером телефона
	
	// TODO: Используйте DeliverMessage для отправки сообщения через каждый messenger
	// и выведите результаты
}
quiz iconПроверьте себя

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

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

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