8.1 Абстрактные классы
Абстрактные классы и методы — ключевые концепции объектно-ориентированного программирования (ООП), которые позволяют создавать шаблоны для других классов. Эти шаблоны определяют общие характеристики и поведение, но объекты этих классов создать нельзя.
Абстрактный класс — это класс, который нельзя непосредственно инстанцировать. Он используется для создания базовых классов, которые служат шаблонами для других классов. Абстрактные классы могут содержать как реализацию методов, так и абстрактные методы, которые нужно реализовать в производных классах.
Синтаксис объявления абстрактного класса
Абстрактный класс объявляется с использованием ключевого слова abstract.
Пример:
"use strict";
class Animal {
constructor(name) {
this.name = name;
}
move(distance) {
console.log(`${this.name} moved ${distance} meters.`);
}
}
// Класс-наследник, который реализует абстрактный метод makeSound
class Dog extends Animal {
constructor(name) {
super(name);
}
makeSound() {
console.log(`${this.name} says: Woof!`);
}
}
// Создаем объект класса Dog и используем его методы
const myDog = new Dog('Rex');
myDog.makeSound(); // Вывод: Rex says: Woof!
myDog.move(10); // Вывод: Rex moved 10 meters.
abstract class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
abstract makeSound(): void; // Абстрактный метод
move(distance: number): void {
console.log(`${this.name} moved ${distance} meters.`);
}
}
// Класс-наследник, который реализует абстрактный метод makeSound
class Dog extends Animal {
constructor(name: string) {
super(name);
}
makeSound(): void {
console.log(`${this.name} says: Woof!`);
}
}
// Создаем объект класса Dog и используем его методы
const myDog = new Dog('Rex');
myDog.makeSound(); // Вывод: Rex says: Woof!
myDog.move(10); // Вывод: Rex moved 10 meters.
Здесь класс Animal — абстрактный, и он содержит абстрактный метод makeSound, который нужно реализовать в производных классах. Также класс содержит метод move, который имеет реализацию.
Производные классы и реализация абстрактных методов
Производные классы, наследующие абстрактный класс, должны реализовать все его абстрактные методы. Если производный класс не реализует все абстрактные методы, его также нужно объявить как абстрактный.
Пример:
"use strict";
class Animal {
constructor(name) {
this.name = name;
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
// Реализация абстрактных методов
makeSound() {
console.log('Woof! Woof!');
}
move(distance) {
console.log(`${this.name} moved ${distance} meters.`);
}
}
let dog = new Dog('Rex');
dog.makeSound(); // Вывод: Woof! Woof!
dog.move(10); // Вывод: Rex moved 10 meters.
abstract class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
// Абстрактные методы, которые должны реализовать все производные классы
abstract makeSound(): void;
abstract move(distance: number): void;
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
// Реализация абстрактных методов
makeSound(): void {
console.log('Woof! Woof!');
}
move(distance: number): void {
console.log(`${this.name} moved ${distance} meters.`);
}
}
let dog = new Dog('Rex');
dog.makeSound(); // Вывод: Woof! Woof!
dog.move(10); // Вывод: Rex moved 10 meters.
В этом примере класс Dog наследует абстрактный класс Animal и реализует метод makeSound.
8.2 Абстрактные методы
Абстрактные методы объявляются в абстрактных классах без реализации. Эти методы должны быть реализованы в производных классах. Или производный класс также нужно объявить абстрактным.
Синтаксис абстрактных методов
Абстрактные методы объявляются с использованием ключевого слова abstract и не содержат тела метода.
Пример:
"use strict";
class Shape {
display() {
console.log(`Area: ${this.calculateArea()}`);
}
}
class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}
calculateArea() {
return Math.PI * this.radius * this.radius;
}
}
let circle = new Circle(5);
circle.display(); // Вывод: Area: 78.53981633974483
abstract class Shape {
abstract calculateArea(): number; // Абстрактный метод
display(): void {
console.log(`Area: ${this.calculateArea()}`);
}
}
class Circle extends Shape {
radius: number;
constructor(radius: number) {
super();
this.radius = radius;
}
calculateArea(): number {
return Math.PI * this.radius * this.radius;
}
}
let circle = new Circle(5);
circle.display(); // Вывод: Area: 78.53981633974483
Здесь абстрактный метод calculateArea объявлен в абстрактном классе Shape и реализован в производном классе Circle.
8.3 Примеры
Абстрактные классы и методы широко используются для создания шаблонов классов, обеспечивающих общие интерфейсы и функциональность. Рассмотрим несколько примеров.
Пример 1: Иерархия транспортных средств
"use strict";
class Vehicle {
constructor(make, model) {
this.make = make;
this.model = model;
}
move(distance) {
console.log(`${this.make} ${this.model} moved ${distance} meters.`);
}
}
class Car extends Vehicle {
constructor(make, model) {
super(make, model);
}
startEngine() {
console.log(`The engine of ${this.make} ${this.model} is started.`);
}
}
let car = new Car('Toyota', 'Camry');
car.startEngine(); // Вывод: The engine of Toyota Camry is started.
car.move(50); // Вывод: Toyota Camry moved 50 meters.
abstract class Vehicle {
make: string;
model: string;
constructor(make: string, model: string) {
this.make = make;
this.model = model;
}
abstract startEngine(): void; // Абстрактный метод
move(distance: number): void {
console.log(`${this.make} ${this.model} moved ${distance} meters.`);
}
}
class Car extends Vehicle {
constructor(make: string, model: string) {
super(make, model);
}
startEngine(): void {
console.log(`The engine of ${this.make} ${this.model} is started.`);
}
}
let car = new Car('Toyota', 'Camry');
car.startEngine(); // Вывод: The engine of Toyota Camry is started.
car.move(50); // Вывод: Toyota Camry moved 50 meters.
Здесь абстрактный класс Vehicle содержит абстрактный метод startEngine и метод move. Производный класс Car реализует метод startEngine.
Пример 2: Моделирование сотрудников компании
"use strict";
class Employee {
constructor(name, position) {
this.name = name;
this.position = position;
}
displayDetails() {
console.log(`Name: ${this.name}, Position: ${this.position}, Salary: ${this.calculateSalary()}`);
}
}
class FullTimeEmployee extends Employee {
constructor(name, position, annualSalary) {
super(name, position);
this.annualSalary = annualSalary;
}
calculateSalary() {
return this.annualSalary;
}
}
class PartTimeEmployee extends Employee {
constructor(name, position, hourlyRate, hoursWorked) {
super(name, position);
this.hourlyRate = hourlyRate;
this.hoursWorked = hoursWorked;
}
calculateSalary() {
return this.hourlyRate * this.hoursWorked;
}
}
let fullTimeEmployee = new FullTimeEmployee('Alice', 'Manager', 80000);
fullTimeEmployee.displayDetails(); // Вывод: Name: Alice, Position: Manager, Salary: 80000
let partTimeEmployee = new PartTimeEmployee('Bob', 'Consultant', 50, 120);
partTimeEmployee.displayDetails(); // Вывод: Name: Bob, Position: Consultant, Salary: 6000
abstract class Employee {
name: string;
position: string;
constructor(name: string, position: string) {
this.name = name;
this.position = position;
}
abstract calculateSalary(): number; // Абстрактный метод
displayDetails(): void {
console.log(`Name: ${this.name}, Position: ${this.position}, Salary: ${this.calculateSalary()}`);
}
}
class FullTimeEmployee extends Employee {
annualSalary: number;
constructor(name: string, position: string, annualSalary: number) {
super(name, position);
this.annualSalary = annualSalary;
}
calculateSalary(): number {
return this.annualSalary;
}
}
class PartTimeEmployee extends Employee {
hourlyRate: number;
hoursWorked: number;
constructor(name: string, position: string, hourlyRate: number, hoursWorked: number) {
super(name, position);
this.hourlyRate = hourlyRate;
this.hoursWorked = hoursWorked;
}
calculateSalary(): number {
return this.hourlyRate * this.hoursWorked;
}
}
let fullTimeEmployee = new FullTimeEmployee('Alice', 'Manager', 80000);
fullTimeEmployee.displayDetails(); // Вывод: Name: Alice, Position: Manager, Salary: 80000
let partTimeEmployee = new PartTimeEmployee('Bob', 'Consultant', 50, 120);
partTimeEmployee.displayDetails(); // Вывод: Name: Bob, Position: Consultant, Salary: 6000
Здесь абстрактный класс Employee содержит абстрактный метод calculateSalary, который реализуется в производных классах FullTimeEmployee и PartTimeEmployee.
Преимущества использования абстрактных классов и методов
- Структурированность и организация кода: абстрактные классы помогают создать четкую иерархию классов, обеспечивая общие интерфейсы и функциональность.
- Повторное использование кода: общие методы и свойства можно определить в абстрактных классах и использовать в производных классах, что уменьшает дублирование кода.
- Гарантия реализации методов: абстрактные методы гарантируют, что производные классы реализуют определенные методы, что обеспечивает согласованность и предсказуемость поведения классов.
- Улучшение читаемости и поддержки кода: абстрактные классы и методы делают код более читаемым и понятным, так как они четко определяют, какие методы должны быть реализованы в производных классах.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ