Как в Go можно эмулировать поведение абстрактного класса?

Ответ

В Go нет концепции абстрактных классов. Однако их поведение — сочетание общего состояния и обязательного для реализации контракта — эмулируется с помощью комбинации встраивания структур (embedding) и интерфейсов.

  1. Общее состояние и методы выносятся в базовую структуру.
  2. Абстрактные методы (контракт) описываются в интерфейсе.

Пример:

Представим, что нам нужен "абстрактный" класс Animal с полем name и методом Eat(), а также абстрактным методом Speak().

package main

import "fmt"

// 1. Базовая структура с общим состоянием и поведением
type BaseAnimal struct {
    name string
}

func (a *BaseAnimal) Eat() {
    fmt.Printf("%s ест.n", a.name)
}

// 2. Интерфейс, определяющий обязательный контракт
type Animal interface {
    Speak() string
    Eat()
}

// 3. "Конкретный класс" Dog
type Dog struct {
    BaseAnimal // Встраиваем базовую структуру
}

// Реализуем обязательный метод Speak()
func (d *Dog) Speak() string {
    return "Гав!"
}

func main() {
    // Убедимся, что Dog удовлетворяет интерфейсу Animal
    var animal Animal

    dog := &Dog{
        BaseAnimal: BaseAnimal{name: "Рекс"},
    }

    animal = dog
    animal.Eat() // Вызовется метод из BaseAnimal
    fmt.Println(animal.Speak()) // Вызовется метод из Dog
}

Таким образом, Dog получает поле name и метод Eat() от BaseAnimal и при этом обязан реализовать метод Speak() для соответствия интерфейсу Animal.