← Назад к вопросам

Что такое интерфейс в ООП?

1.6 Junior🔥 261 комментариев
#Основы Go

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое интерфейс в ООП?

Интерфейс — это абстрактный контракт, который определяет набор методов, которые должен реализовать тип данных, не навязывая как это реализовать. Это один из столпов объектно-ориентированного программирования.

Концепция интерфейса

Интерфейс — это договор:

type Writer interface {
    Write([]byte) (int, error)
}

Это говорит: "Если тип реализует метод Write, то он считается Writer". Это всё. Никаких явных объявлений наследования.

Основные принципы

1. Полиморфизм

Интерфейсы позволяют работать с разными типами единообразно:

type Animal interface {
    Speak() string
    Move() string
}

type Dog struct{}
func (d Dog) Speak() string { return "Woof" }
func (d Dog) Move() string { return "Running" }

type Cat struct{}
func (c Cat) Speak() string { return "Meow" }
func (c Cat) Move() string { return "Walking" }

func MakeAnimalAct(a Animal) {
    fmt.Println(a.Speak())
    fmt.Println(a.Move())
}

// Функция работает с любым Animal
MakeAnimalAct(Dog{})  // Woof, Running
MakeAnimalAct(Cat{})  // Meow, Walking

2. Слабая типизация (Duck Typing)

В Go нет явного "implements" ключевого слова. Если тип реализует все методы интерфейса, он автоматически его реализует. Это называется неявная реализация (implicit satisfaction):

type Reader interface {
    Read([]byte) (int, error)
}

// os.File реализует Reader потому что у неё есть метод Read
// Но File НЕ явно заявляет "я реализую Reader"
// Это просто работает автоматически

var r Reader
r = os.Open("file.txt")  // *File автоматически совместим с Reader

Стандартные интерфейсы Go

io.Reader и io.Writer:

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

Эти интерфейсы используются везде в стандартной библиотеке.

io.ReadWriter:

type ReadWriter interface {
    Reader
    Writer
}

Интерфейсы могут встраивать другие интерфейсы (композиция интерфейсов).

error интерфейс:

type error interface {
    Error() string
}

Каждая функция может вернуть ошибку через этот интерфейс.

Практические примеры

1. Логирование разных типов вывода:

type Logger interface {
    Log(message string)
}

type ConsoleLogger struct{}
func (cl ConsoleLogger) Log(msg string) {
    fmt.Println("[CONSOLE]:", msg)
}

type FileLogger struct {
    file *os.File
}
func (fl FileLogger) Log(msg string) {
    fl.file.WriteString(msg + "\n")
}

func LogMessage(logger Logger, msg string) {
    logger.Log(msg)  // работает с любым Logger
}

// Использование
LogMessage(ConsoleLogger{}, "Error occurred")
LogMessage(FileLogger{file: logFile}, "Error occurred")

2. Работа с разными хранилищами данных:

type Repository interface {
    Save(ctx context.Context, item interface{}) error
    Get(ctx context.Context, id string) (interface{}, error)
    Delete(ctx context.Context, id string) error
}

type PostgresRepository struct {
    db *sql.DB
}

type MongoRepository struct {
    client *mongo.Client
}

// Обе реализуют Repository интерфейс
// Сервис может работать с любым Repository
type UserService struct {
    repo Repository
}

func (us *UserService) CreateUser(ctx context.Context, user User) error {
    return us.repo.Save(ctx, user)  // не важно какой репо
}

3. io.Copy работает с любыми Reader/Writer:

// Это универсальная функция из stdlib
func Copy(dst Writer, src Reader) (written int64, err error)

// Работает с файлами
file, _ := os.Open("source.txt")
io.Copy(os.Stdout, file)

// Работает с буфферами
buf := new(bytes.Buffer)
io.Copy(buf, file)

// Работает с network соединениями
conn, _ := net.Dial("tcp", "localhost:8080")
io.Copy(conn, file)

Интерфейсы как аргументы функций

ХОРОШО — функция принимает минимально необходимый интерфейс:

func WriteLog(w io.Writer, msg string) error {
    _, err := w.Write([]byte(msg))
    return err
}

// Можно вызвать с файлом
f, _ := os.Create("log.txt")
WriteLog(f, "message")

// Можно с буфером
buf := new(bytes.Buffer)
WriteLog(buf, "message")

// Можно с сетевым соединением
conn, _ := net.Dial("tcp", "localhost:9000")
WriteLog(conn, "message")

ПЛОХО — функция требует конкретный тип:

func WriteLog(f *os.File, msg string) error {
    _, err := f.WriteString(msg)
    return err
}
// Теперь можно только с os.File, не работает с буфером

Interface{} — пустой интерфейс

Пустой интерфейс может быть реализован ЛЮБЫМ типом:

var x interface{}
x = 42              // int
x = "hello"        // string
x = []int{1, 2, 3} // []int

// Используется для работы с неизвестными типами
func Print(v interface{}) {
    fmt.Println(v)
}

// Type assertion для получения оригинального типа
if str, ok := x.(string); ok {
    fmt.Println("It's a string:", str)
}

Embedded интерфейсы

type Reader interface {
    Read([]byte) (int, error)
}

type Writer interface {
    Write([]byte) (int, error)
}

type ReadWriter interface {
    Reader   // встраиваем
    Writer   // встраиваем
}

// ReadWriter включает все методы Reader и Writer
var rw ReadWriter
rw.Read(make([]byte, 10))
rw.Write(make([]byte, 5))

Важные правила

  1. Интерфейсы должны быть маленькими — одна или несколько связанных методов
// Хорошо
type Reader interface {
    Read([]byte) (int, error)
}

// Плохо — слишком большой интерфейс
type DataStore interface {
    Read([]byte) (int, error)
    Write([]byte) (int, error)
    Delete(id string) error
    List() []Item
    Save(item Item) error
    // ... ещё 10 методов
}
  1. Пиши функции, которые принимают интерфейсы, возвращают конкретные типы
// Хорошо
func NewBuffer(r io.Reader) *bytes.Buffer

// Плохо
func NewBuffer(r io.Reader) io.Reader
  1. Не экспортируй интерфейсы если не нужно — обычно нужны внутри пакета
// Хорошо
type reader interface {  // lowercase
    Read([]byte) (int, error)
}

// Плохо
type Reader interface {  // exported, когда это не нужно
    Read([]byte) (int, error)
}

Вывод

Интерфейс в ООП и Go:

  • Определяет контракт методов
  • Обеспечивает полиморфизм
  • Снижает связанность между компонентами
  • В Go реализуются неявно (duck typing)
  • Ключ к расширяемому и поддерживаемому коду
  • Стандартная библиотека построена на интерфейсах (io.Reader, io.Writer, error и т.д.)

Мастерское использование интерфейсов — это одна из главных навыков Go разработчика.

Что такое интерфейс в ООП? | PrepBro