← Назад к вопросам

Какие знаешь принципы ООП?

1.6 Junior🔥 251 комментариев
#JavaScript Core#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Какие знаешь принципы ООП?

Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на концепции объектов, которые содержат данные и методы. Существует четыре основных принципа ООП, которые являются фундаментом для написания чистого и масштабируемого кода.

Четыре основных принципа ООП

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 коде делает программу более профессиональной и надежной.