← Назад к вопросам
В чем разница между abstract class и interface?
2.0 Middle🔥 171 комментариев
#TypeScript#ООП
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
В чем разница между abstract class и interface?
Быстрое сравнение
| Аспект | Abstract Class | Interface |
|---|---|---|
| Наследование | extends | implements |
| Множественное наследование | Только одна | Несколько |
| Свойства (поля) | Могут быть | Только сигнатуры |
| Методы с реализацией | Есть | Нет (но можно в 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 = только контракт, нет реализации
Выбор между ними влияет на архитектуру, гибкость и переиспользуемость кода.