TypeScript: Абстрактные классы
Когда нам нужно определить общее поведение для нескольких классов, удобно использовать абстрактные классы, которые хоть и не могут быть созданы напрямую, но могут быть наследованы и указать явно какой метод должен быть реализован в наследниках.
abstract class File {
protected name: string;
protected size: number;
constructor(name: string, size: number) {
this.name = name;
this.size = size;
}
sizeInKb(): number {
return this.size / 1024;
}
}
class ImageFile extends File {
constructor(name: string, size: number) {
super(name, size);
}
}
Кроме того, чтобы выносить из классов общую часть кода абстрактные классы активно используются для построения архитектуры приложения и фреймворков. Например, в React есть класс Component
, который может быть представлен как абстрактный класс. Его мы не можем создать напрямую, но он требует от наследников реализации метода render
. Это позволяет создавать компоненты, которые будут рендериться при инициализации:
abstract class Component {
abstract render(): void;
constructor() {
this.render();
}
}
Задание
Мы разрабатываем фреймворк для создания игр. Наша задача - создать абстрактный класс GameObject
, который будет содержать общую логику для всех игровых объектов. Каждый игровой объект должен иметь координаты x
, y
на игровом поле. Также должен иметь методы move(x, y)
, который накапливает смещения по осям x
и y
и метод tick(delta)
, который обновляет координаты на основе накопленных смещений умножить на delta
. После обновления координаты смещения должны обнуляться. Все игровые объекты должны иметь метод render()
, который отрисовывает их на игровом поле.
class Player extends GameObject {
render(): string {
return `Player: ${this.x}, ${this.y}`;
}
}
class Enemy extends GameObject {
render(): string {
return `Enemy: ${this.x}, ${this.y}`;
}
}
const scene = new GameScene();
const player = new Player(0, 0);
const enemy = new Enemy(20, 20);
scene.addObject(player);
scene.addObject(enemy);
player.move(10, 10);
enemy.move(20, 20);
player.move(10, 10);
scene.tick(0.5);
console.log(scene.render());
// Player: 5, 5
// Enemy: 30, 30
scene.tick(1);
console.log(scene.render());
// Player: 15, 15
// Enemy: 30, 30
Упражнение не проходит проверку — что делать? 😶
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
- Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Мой код отличается от решения учителя 🤔
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Прочитал урок — ничего не понятно 🙄
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Полезное
Определения
Абстрактный класс — это класс, который не может быть создан напрямую. Он предназначен только для наследования. Для создания абстрактного класса используется ключевое слово
abstract
.