Что такое принципы ООП?

👨‍💻 Frontend Developer 🟠 Может встретиться 🎚️ Сложный
#ООП #Теория

Краткий ответ

Объектно-ориентированное программирование (ООП) — это парадигма программирования, основанная на четырех основных принципах:

  1. Инкапсуляция: Сокрытие внутренней реализации объекта и предоставление доступа к его состоянию только через публичные методы. Данные и методы, которые с ними работают, объединяются в один компонент — объект.
  2. Наследование: Механизм, который позволяет одному классу (потомку) перенимать свойства и методы другого класса (родителя). Это способствует повторному использованию кода.
  3. Полиморфизм: Способность объектов с разными классами отвечать на один и тот же вызов метода по-разному. Это позволяет использовать единый интерфейс для работы с объектами разных типов.
  4. Абстракция: Выделение наиболее значимых характеристик объекта и игнорирование второстепенных. Пользователю предоставляется только необходимый функционал, а сложная реализация скрывается.

Развернутый ответ с примерами

1. Инкапсуляция

Инкапсуляция — это объединение данных и методов для их обработки в одном объекте, а также защита этих данных от внешнего вмешательства. Доступ к данным контролируется через публичные методы (геттеры и сеттеры).

В JavaScript инкапсуляцию можно реализовать с помощью классов и приватных полей (с использованием #).

Пример:

class User {
  #email; // Приватное поле
 
  constructor(name, email) {
    this.name = name;
    this.#email = email;
  }
 
  // Публичный метод для получения email (геттер)
  getEmail() {
    return this.#email;
  }
 
  // Публичный метод для изменения email (сеттер)
  setEmail(newEmail) {
    if (newEmail.includes('@')) {
      this.#email = newEmail;
    } else {
      console.error('Ошибка: некорректный email');
    }
  }
 
  getInfo() {
    // Внутренние методы могут работать с приватными полями
    return `Пользователь: ${this.name}, Email: ${this.#email}`;
  }
}
 
const user = new User('Иван', 'ivan@test.com');
console.log(user.name); // 'Иван'
// console.log(user.#email); // Ошибка! Доступа к приватному полю нет
 
console.log(user.getEmail()); // 'ivan@test.com'
user.setEmail('new-email@test.com');
console.log(user.getEmail()); // 'new-email@test.com'
user.setEmail('invalid-email'); // Ошибка: некорректный email

2. Наследование

Наследование позволяет создавать новый класс на основе существующего, перенимая его свойства и методы. Это способствует повторному использованию кода и созданию иерархии классов.

Пример:

class Animal {
  constructor(name) {
    this.name = name;
  }
 
  makeSound() {
    console.log('Животное издает звук');
  }
}
 
// Класс Dog наследует от Animal
class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Вызов конструктора родительского класса
    this.breed = breed;
  }
 
  // Переопределение родительского метода
  makeSound() {
    console.log('Собака лает: Гав-гав!');
  }
 
  // Собственный метод класса Dog
  wagTail() {
    console.log(`${this.name} виляет хвостом.`);
  }
}
 
const myDog = new Dog('Рекс', 'Овчарка');
myDog.makeSound(); // 'Собака лает: Гав-гав!'
myDog.wagTail(); // 'Рекс виляет хвостом.'
console.log(myDog.name); // 'Рекс' (унаследовано от Animal)

3. Полиморфизм

Полиморфизм (от греч. «много форм») — это способность функции или метода обрабатывать данные разных типов. В контексте ООП это означает, что объекты разных классов могут по-разному реагировать на один и тот же вызов метода.

В примере выше полиморфизм проявляется в том, что метод makeSound() существует как в классе Animal, так и в классе Dog, но работает по-разному.

Пример:

class Cat extends Animal {
  makeSound() {
    console.log('Кошка мяукает: Мяу!');
  }
}
 
const animals = [
  new Animal('Зверь'),
  new Dog('Бобик', 'Дворняга'),
  new Cat('Мурка', 'Сиамская')
];
 
// Единый интерфейс для работы с разными объектами
function printSound(animalList) {
  for (const animal of animalList) {
    animal.makeSound();
  }
}
 
printSound(animals);
// Вывод:
// Животное издает звук
// Собака лает: Гав-гав!
// Кошка мяукает: Мяу!

Здесь мы вызываем один и тот же метод makeSound() для разных объектов, и каждый из них выполняет свою реализацию.

4. Абстракция

Абстракция — это сокрытие сложной логики и предоставление простого интерфейса для взаимодействия. Пользователю не нужно знать, как работает метод, ему достаточно знать, что он делает.

Классы сами по себе являются формой абстракции. Когда мы создаем объект, мы работаем с его методами, не задумываясь об их внутренней реализации.

Пример:

Представьте себе сложный объект, например, CoffeeMachine.

class CoffeeMachine {
  #waterLevel; // Скрытые детали
 
  constructor() {
    this.#waterLevel = 0;
  }
 
  #heatWater() {
    console.log('Нагреваем воду...');
  }
 
  #grindCoffee() {
    console.log('Перемалываем зерна...');
  }
 
  // Публичный метод - простая абстракция
  makeEspresso() {
    this.#grindCoffee();
    this.#heatWater();
    console.log('Ваш эспрессо готов!');
  }
}
 
const machine = new CoffeeMachine();
machine.makeEspresso(); // Мы просто вызываем один метод
 
// Нам не нужно знать о #heatWater() или #grindCoffee()
// Вся сложность скрыта за простым интерфейсом.

Пользователь просто вызывает makeEspresso(), и кофемашина делает все сама. Это и есть абстракция — предоставление простого интерфейса для выполнения сложной задачи.