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

В чем разница между abstract class и interface?

2.0 Middle🔥 171 комментариев
#TypeScript#ООП

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

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

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

В чем разница между abstract class и interface?

Быстрое сравнение

АспектAbstract ClassInterface
Наследованиеextendsimplements
Множественное наследованиеТолько однаНесколько
Свойства (поля)Могут бытьТолько сигнатуры
Методы с реализациейЕстьНет (но можно в TS)
Access модификаторыВсе (public, private, protected)Только public
КонструкторМожет бытьНет

Abstract Class (Абстрактный класс)

Назначение: Определить общую реализацию и структуру для подклассов.

abstract class Animal {
  // Свойство с начальным значением
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  // Конкретная реализация
  sleep(): void {
    console.log(`${this.name} спит`);
  }

  // Абстрактный метод (должна быть реализация в подклассе)
  abstract makeSound(): void;
}

class Dog extends Animal {
  makeSound(): void {
    console.log('Гав!');
  }
}

const dog = new Dog('Шарик');
dog.sleep();      // Ок, наследуется
dog.makeSound();  // Гав!

Ключевые особенности:

  • Содержит реализацию некоторых методов
  • Может иметь приватные и защищённые поля
  • Может иметь конструктор
  • Поддерживает только одного родителя (inheritance)

Interface (Интерфейс)

Назначение: Определить контракт (договор) о наличии определённых методов и свойств.

interface Animal {
  name: string;
  age: number;
  makeSound(): void;
  sleep(): void;
}

class Dog implements Animal {
  name: string;
  age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  makeSound(): void {
    console.log('Гав!');
  }

  sleep(): void {
    console.log(`${this.name} спит`);
  }
}

Ключевые особенности:

  • Только сигнатуры методов (не реализация)
  • Не может иметь реализацию в обычном TypeScript
  • Поддерживает множественную реализацию
  • Нет конструктора
  • Нет приватных полей

Множественная реализация

Один класс может реализовать несколько интерфейсов:

interface Flying {
  fly(): void;
}

interface Swimming {
  swim(): void;
}

class Duck implements Flying, Swimming {
  fly(): void {
    console.log('Утка летит');
  }

  swim(): void {
    console.log('Утка плывёт');
  }
}

Но наследовать можно только один abstract class:

abstract class Bird {
  abstract fly(): void;
}

abstract class Swimmer {
  abstract swim(): void;
}

// ❌ Ошибка! Нельзя наследовать от двух классов
class Duck extends Bird, Swimmer { }

// ✅ Правильно: наследование + реализация интерфейсов
class Duck extends Bird implements Swimmer {
  fly(): void { }
  swim(): void { }
}

Конкретные примеры

Abstract class для базовой функциональности:

abstract class Database {
  protected connectionString: string;

  constructor(connectionString: string) {
    this.connectionString = connectionString;
  }

  // Общий метод для всех БД
  connect(): void {
    console.log('Подключение к базе...');
  }

  // Разные БД реализуют по-своему
  abstract query(sql: string): Promise<any[]>;
  abstract close(): void;
}

class PostgreSQL extends Database {
  async query(sql: string): Promise<any[]> {
    // PostgreSQL специфичная реализация
    return [];
  }

  close(): void {
    console.log('Закрыли PostgreSQL соединение');
  }
}

class MongoDB extends Database {
  async query(sql: string): Promise<any[]> {
    // MongoDB специфичная реализация
    return [];
  }

  close(): void {
    console.log('Закрыли MongoDB соединение');
  }
}

Interface для контракта:

interface Repository<T> {
  getAll(): Promise<T[]>;
  getById(id: string): Promise<T | null>;
  save(item: T): Promise<void>;
  delete(id: string): Promise<void>;
}

class UserRepository implements Repository<User> {
  async getAll(): Promise<User[]> { /* ... */ }
  async getById(id: string): Promise<User | null> { /* ... */ }
  async save(item: User): Promise<void> { /* ... */ }
  async delete(id: string): Promise<void> { /* ... */ }
}

Когда что использовать

Abstract class, если:

  • Нужна общая реализация для нескольких классов
  • Есть состояние (свойства с значениями)
  • Нужны приватные или защищённые члены
  • Логичная иерархия наследования (есть родитель)

Interface, если:

  • Только определяем контракт
  • Класс должен реализовать несколько контрактов
  • Нет общей реализации
  • Нужна гибкость (один интерфейс для разных классов)

Практический вывод

Это ключевое различие в TypeScript/OOP:

  • Abstract class = имеет реализацию + определяет структуру
  • Interface = только контракт, нет реализации

Выбор между ними влияет на архитектуру, гибкость и переиспользуемость кода.

В чем разница между abstract class и interface? | PrepBro