Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Abstract Class (Абстрактные классы)
Абстрактные классы - это специальные классы в объектно-ориентированном программировании, которые определяют интерфейс и общую логику для наследующих их классов, но не могут быть инстанцированы напрямую.
Что такое абстрактный класс?
Абстрактный класс - это класс, содержащий абстрактные методы (без реализации) и конкретные методы (с реализацией). Он служит шаблоном для подклассов.
Зачем нужны абстрактные классы?
1. Определение контракта (интерфейс)
Абстрактный класс задаёт, какие методы должны быть реализованы в подклассах:
class Animal {
// Абстрактный метод - должен быть переопределён
makeSound() {
throw new Error("Method 'makeSound' must be implemented");
}
// Конкретный метод - общая логика
sleep() {
console.log("Zzz...");
}
}
class Dog extends Animal {
makeSound() {
console.log("Woof!");
}
}
const dog = new Dog();
dog.makeSound(); // Woof!
dog.sleep(); // Zzz...
2. Переиспользование кода
Общая логика находится в абстрактном классе, подклассы наследуют её:
class DataProcessor {
process(data) {
const cleaned = this.clean(data);
const validated = this.validate(cleaned);
return this.transform(validated);
}
clean(data) {
throw new Error("Must implement clean()");
}
validate(data) {
throw new Error("Must implement validate()");
}
transform(data) {
throw new Error("Must implement transform()");
}
}
class JSONProcessor extends DataProcessor {
clean(data) {
return data.trim();
}
validate(data) {
return JSON.parse(data); // Выбросит ошибку если невалидный JSON
}
transform(data) {
return data.map(item => ({
...item,
timestamp: new Date()
}));
}
}
3. Полиморфизм
Различные реализации одного интерфейса:
class Shape {
getArea() {
throw new Error("Must implement getArea()");
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
getArea() {
return Math.PI * this.radius ** 2;
}
}
class Rectangle extends Shape {
constructor(width, height) {
super();
this.width = width;
this.height = height;
}
getArea() {
return this.width * this.height;
}
}
const shapes = [new Circle(5), new Rectangle(4, 6)];
shapes.forEach(shape => console.log(shape.getArea()));
4. Предотвращение ошибок
Знание о требуемых методах помогает не забыть реализовать что-то важное:
class Repository {
create(data) {
throw new Error("Must implement create()");
}
read(id) {
throw new Error("Must implement read()");
}
update(id, data) {
throw new Error("Must implement update()");
}
delete(id) {
throw new Error("Must implement delete()");
}
}
// Разработчик видит ВСЕ методы, которые нужно реализовать
class UserRepository extends Repository {
create(user) { /* */ }
read(id) { /* */ }
update(id, user) { /* */ }
delete(id) { /* */ }
}
Отличие от интерфейсов
Абстрактный класс:
- Может содержать конкретные методы с реализацией
- Может иметь свойства с начальными значениями
- Может иметь приватные члены
- Один класс может наследовать только один абстрактный класс
Интерфейс:
- Только сигнатуры методов (в TypeScript)
- Нет реализации
- Один класс может реализовывать несколько интерфейсов
В TypeScript (более явно)
abstract class Vehicle {
abstract start(): void;
drive() {
this.start();
console.log("Driving...");
}
}
class Car extends Vehicle {
start(): void {
console.log("Engine started");
}
}
// const v = new Vehicle(); // Ошибка: Cannot instantiate abstract class
const car = new Car();
car.drive(); // Engine started, Driving...
Когда использовать?
- Создание иерархии классов с общей логикой
- Определение контракта для подклассов
- Реализация паттерна Template Method
- Полиморфное поведение в приложении
Абстрактные классы - мощный инструмент для создания масштабируемого и поддерживаемого кода с чётко определённой архитектурой.