Какие знаешь принципы ООП?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Какие знаешь принципы ООП?
Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на концепции объектов, которые содержат данные и методы. Существует четыре основных принципа ООП, которые являются фундаментом для написания чистого и масштабируемого кода.
Четыре основных принципа ООП
1. Инкапсуляция (Encapsulation)
Инкапсуляция — это скрытие внутренних деталей реализации и предоставление только необходимого интерфейса для взаимодействия с объектом.
// ❌ Плохо: прямой доступ к свойствам
const user = {
name: 'John',
age: 30,
salary: 5000, // Чувствительная информация
};
user.salary = -1000; // Можно установить некорректное значение
// ✅ Хорошо: инкапсуляция через класс
class User {
constructor(name, age, salary) {
this._name = name;
this._age = age;
this._salary = salary; // приватное свойство
}
// Геттер для чтения
getName() {
return this._name;
}
// Сеттер с валидацией
setSalary(salary) {
if (salary < 0) {
throw new Error('Зарплата не может быть отрицательной');
}
this._salary = salary;
}
getSalary() {
return this._salary;
}
}
const user = new User('John', 30, 5000);
user.setSalary(6000); // ✅ валидно
user.setSalary(-1000); // ❌ ошибка
Преимущества:
- Защита данных от некорректных значений
- Контроль доступа к данным
- Возможность менять внутреннюю реализацию без изменения интерфейса
2. Наследование (Inheritance)
Наследование — это механизм, позволяющий одному классу наследовать свойства и методы другого класса. Это способствует переиспользованию кода и создания иерархий классов.
// Базовый класс
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} издает звук`);
}
move() {
console.log(`${this.name} движется`);
}
}
// Класс-наследник
class Dog extends Animal {
constructor(name, breed) {
super(name); // вызов конструктора родителя
this.breed = breed;
}
// Переопределение метода
speak() {
console.log(`${this.name} лает: гав-гав!`);
}
// Новый метод
fetch() {
console.log(`${this.name} принес мяч`);
}
}
const dog = new Dog('Шарик', 'Овчарка');
dog.speak(); // Шарик лает: гав-гав!
dog.move(); // Шарик движется
dog.fetch(); // Шарик принес мяч
Типы наследования:
// Одиночное наследование
class Car extends Vehicle {}
// Многоуровневое наследование
class SportsCar extends Car extends Vehicle {}
// Интерфейсы (в TypeScript)
interface Drawable {
draw(): void;
}
interface Resizable {
resize(width: number, height: number): void;
}
class Shape implements Drawable, Resizable {
draw() { /* ... */ }
resize() { /* ... */ }
}
Преимущества:
- Переиспользование кода
- Создание иерархий и отношений между классами
- Упрощение программы через абстракцию
3. Полиморфизм (Polymorphism)
Полиморфизм — это способность объектов одного типа вести себя как объекты другого типа. Это позволяет использовать различные реализации одного и того же интерфейса.
// Полиморфизм через переопределение методов
class Shape {
getArea() {
throw new Error('Метод должен быть переопределён');
}
}
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;
}
}
// Полиморфное использование
function printArea(shape) {
console.log(`Площадь: ${shape.getArea()}`);
}
const circle = new Circle(5);
const rectangle = new Rectangle(10, 20);
printArea(circle); // Площадь: 78.53981633974483
printArea(rectangle); // Площадь: 200
// Один и тот же вызов, разные реализации!
Виды полиморфизма:
// 1. Полиморфизм времени выполнения (динамический)
class Animal {
speak() {
console.log('Издает звук');
}
}
class Cat extends Animal {
speak() {
console.log('Мяу');
}
}
const animals = [new Dog(), new Cat(), new Animal()];
animals.forEach(animal => animal.speak()); // разные реализации
// 2. Перегрузка методов (в TypeScript)
class Calculator {
add(a: number, b: number): number;
add(a: string, b: string): string;
add(a: any, b: any): any {
return a + b;
}
}
const calc = new Calculator();
calc.add(5, 10); // 15 (числа)
calc.add('5', '10'); // '510' (строки)
Преимущества:
- Гибкость и расширяемость кода
- Возможность работать с объектами через общий интерфейс
- Упрощение кода через абстракцию
4. Абстракция (Abstraction)
Абстракция — это скрытие сложности и предоставление только необходимых деталей. Это позволяет пользователю сосредоточиться на том, что делает объект, не волнуясь о том, как это делается.
// ❌ Плохо: сложная реализация видна
class Car {
startEngine() {
// 100 строк кода с деталями запуска двигателя
this.checkFuel();
this.checkBattery();
this.igniteSparkPlugs();
this.startMotor();
this.checkOilPressure();
// ...
}
}
// ✅ Хорошо: абстракция скрывает сложность
class Car {
startEngine() {
// Пользователь видит только необходимое
console.log('Двигатель запущен');
}
// Приватные методы скрыты
#checkFuel() { /* ... */ }
#checkBattery() { /* ... */ }
#igniteSparkPlugs() { /* ... */ }
}
// Использование просто и понятно
const car = new Car();
car.startEngine(); // Только это видит пользователь
Пример абстрактного класса (TypeScript):
// Абстрактный класс определяет интерфейс
abstract class DatabaseConnection {
abstract connect(): void;
abstract disconnect(): void;
abstract query(sql: string): void;
}
// Конкретная реализация
class MySQLConnection extends DatabaseConnection {
connect() {
console.log('Подключение к MySQL...');
}
disconnect() {
console.log('Отключение от MySQL...');
}
query(sql: string) {
console.log(`Выполнение SQL: ${sql}`);
}
}
const db = new MySQLConnection();
db.connect(); // Пользователь не знает деталей реализации
db.query('SELECT *'); // Просто использует метод
Преимущества:
- Снижение сложности для пользователя
- Возможность менять внутреннюю реализацию
- Лучшая читаемость кода
Практический пример: банковская система
// 1. Инкапсуляция: скрытие баланса
// 2. Наследование: пользователь наследуется от базового класса
// 3. Полиморфизм: разные типы пользователей по-разному используют систему
// 4. Абстракция: пользователь не знает как работает система
class BankUser {
#balance = 0; // приватное свойство (инкапсуляция)
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
}
}
getBalance() {
return this.#balance;
}
}
class RegularUser extends BankUser {
getInterestRate() {
return 2; // 2%
}
}
class PremiumUser extends BankUser {
getInterestRate() {
return 5; // 5% (полиморфизм)
}
}
// Абстракция: пользователь не знает как считается процент
function applyInterest(user) {
const rate = user.getInterestRate();
const balance = user.getBalance();
user.deposit(balance * rate / 100);
}
const regular = new RegularUser();
const premium = new PremiumUser();
regular.deposit(1000);
premium.deposit(1000);
applyInterest(regular); // 2% процента
applyInterest(premium); // 5% процентов
Связанные принципы SOLID
В современной разработке часто используются принципы SOLID, которые расширяют ООП:
- Single Responsibility — одна ответственность
- Open/Closed — открыто для расширения, закрыто для модификации
- Liskov Substitution — принцип подстановки
- Interface Segregation — разделение интерфейсов
- Dependency Inversion — инверсия зависимостей
Итог
Четыре принципа ООП (инкапсуляция, наследование, полиморфизм, абстракция) являются основой для написания чистого, масштабируемого и поддерживаемого кода. Они позволяют создавать гибкие архитектуры, которые легко расширяются и изменяются. Правильное применение этих принципов в JavaScript/TypeScript коде делает программу более профессиональной и надежной.