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

Какие знаешь принципы объектно-ориентированного программирования?

1.0 Junior🔥 241 комментариев
#Архитектура и паттерны

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

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

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

Какие знаешь принципы объектно-ориентированного программирования?

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

1. SOLID принципы

S — Single Responsibility Principle (Единственная ответственность) Каждый класс или функция должны иметь одну зону ответственности:

// ❌ Нарушает SRP — слишком много ответственности
class User {
  validateEmail(email) { /* ... */ }
  saveToDatabase(user) { /* ... */ }
  sendEmail(email) { /* ... */ }
  generateReport(user) { /* ... */ }
}

// ✅ Следует SRP — каждый класс делает одно
class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }
}

class EmailValidator {
  validate(email) { /* ... */ }
}

class UserRepository {
  save(user) { /* ... */ }
}

class EmailService {
  send(email, subject, body) { /* ... */ }
}

class ReportGenerator {
  generate(user) { /* ... */ }
}

O — Open/Closed Principle (Открыто для расширения, закрыто для модификации) Класс должен быть открыт для расширения, но закрыт для изменения:

// ❌ Неправильно — нужно изменять класс при добавлении новых типов
class PaymentProcessor {
  process(type, amount) {
    if (type === 'credit-card') {
      // логика кредитной карты
    } else if (type === 'paypal') {
      // логика PayPal
    } else if (type === 'bitcoin') {
      // логика Bitcoin
    }
  }
}

// ✅ Правильно — расширяется через наследование
class PaymentMethod {
  process(amount) {
    throw new Error('Must be implemented');
  }
}

class CreditCardPayment extends PaymentMethod {
  process(amount) { /* ... */ }
}

class PayPalPayment extends PaymentMethod {
  process(amount) { /* ... */ }
}

class BitcoinPayment extends PaymentMethod {
  process(amount) { /* ... */ }
}

class PaymentProcessor {
  constructor(paymentMethod) {
    this.paymentMethod = paymentMethod;
  }
  
  process(amount) {
    return this.paymentMethod.process(amount);
  }
}

L — Liskov Substitution Principle (Подстановка Лисков) Объект родительского класса можно заменить объектом подкласса без нарушения функциональности:

// ❌ Нарушает LSP
class Bird {
  fly() { return 'flying'; }
}

class Penguin extends Bird {
  fly() { throw new Error('Cannot fly'); } // Нарушение контракта
}

// ✅ Правильно
class Animal {}

class FlyingBird extends Animal {
  fly() { return 'flying'; }
}

class SwimmingBird extends Animal {
  swim() { return 'swimming'; }
}

class Penguin extends SwimmingBird {
  swim() { return 'swimming'; }
}

I — Interface Segregation Principle (Разделение интерфейса) Не заставляй класс реализовывать методы, которые он не использует:

// ❌ Нарушает ISP
class Worker {
  work() { }
  manage() { }
  report() { }
}

class Developer extends Worker {
  work() { /* программирует */ }
  manage() { throw new Error('Not applicable'); }
  report() { throw new Error('Not applicable'); }
}

// ✅ Правильно
class Workable {
  work() { }
}

class Manageable {
  manage() { }
}

class Reportable {
  report() { }
}

class Developer implements Workable {
  work() { /* программирует */ }
}

class Manager implements Workable, Manageable, Reportable {
  work() { /* управляет */ }
  manage() { /* управляет */ }
  report() { /* отчитывается */ }
}

D — Dependency Inversion Principle (Инверсия зависимостей) Зависи от абстракций, не от конкретных реализаций:

// ❌ Высокоуровневый модуль зависит от низкоуровневого
class MySQLDatabase {
  save(data) { /* ... */ }
}

class UserService {
  constructor() {
    this.db = new MySQLDatabase(); // Жесткая зависимость
  }
}

// ✅ Используй инъекцию зависимостей
class UserService {
  constructor(database) {
    this.db = database; // Зависит от интерфейса, не реализации
  }
}

// Использование
const mysqlDb = new MySQLDatabase();
const userService = new UserService(mysqlDb);

// Легко тестировать
const mockDb = { save: () => {} };
const testService = new UserService(mockDb);

2. Основные принципы ООП

Инкапсуляция (Encapsulation) Хранение данных и методов вместе, скрытие внутренней реализации:

class BankAccount {
  #balance = 0;  // Private поле
  
  constructor(initialBalance) {
    this.#balance = initialBalance;
  }
  
  deposit(amount) {
    if (amount > 0) this.#balance += amount;
  }
  
  getBalance() {  // Public метод для доступа
    return this.#balance;
  }
}

const account = new BankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
console.log(account.#balance);     // Error — приватно

Наследование (Inheritance) Создание новых классов на основе существующих:

class Animal {
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    return `${this.name} makes a sound`;
  }
}

class Dog extends Animal {
  speak() {
    return `${this.name} barks`;
  }
  
  fetch() {
    return `${this.name} is fetching`;
  }
}

const dog = new Dog('Rex');
console.log(dog.speak());  // Rex barks
console.log(dog.fetch());  // Rex is fetching

Полиморфизм (Polymorphism) Один интерфейс, много реализаций:

class Shape {
  area() {
    throw new Error('Must be implemented');
  }
}

class Circle extends Shape {
  constructor(radius) {
    super();
    this.radius = radius;
  }
  
  area() {
    return Math.PI * this.radius ** 2;
  }
}

class Rectangle extends Shape {
  constructor(width, height) {
    super();
    this.width = width;
    this.height = height;
  }
  
  area() {
    return this.width * this.height;
  }
}

const shapes = [new Circle(5), new Rectangle(4, 6)];
shapes.forEach(shape => {
  console.log(shape.area()); // Полиморфизм — каждый вычисляет по-своему
});

Абстракция (Abstraction) Сокрытие сложности, предоставление простого интерфейса:

// Сложная реализация скрыта
class FileSystem {
  #readFromDisk(path) { /* сложная логика */ }
  #parseJSON(content) { /* сложная логика */ }
  
  loadConfig(path) {
    return this.#parseJSON(this.#readFromDisk(path));
  }
}

// Пользователь видит только простой интерфейс
const fs = new FileSystem();
const config = fs.loadConfig('/config/app.json');

3. ООП в React (функциональный подход)

Хотя React предпочитает функциональный подход, ООП принципы все еще актуальны:

// ✅ Применение принципов в React
function Button({ onClick, children, variant = 'primary' }) {
  // S — Single Responsibility: только рендер кнопки
  return (
    <button onClick={onClick} className={`btn btn-${variant}`}>
      {children}
    </button>
  );
}

// O — Open/Closed: расширяется через props
<Button variant="secondary">Отмена</Button>

// Хук для инкапсуляции логики
function useToggle(initialState = false) {
  const [state, setState] = useState(initialState);
  const toggle = useCallback(() => setState(s => !s), []);
  return [state, toggle];
}

4. Когда применять ООП

Хорошо подходит для:

  • Сложных бизнес-логик
  • Реализации паттернов (Singleton, Observer, etc.)
  • Большие приложения с иерархией классов

JavaScript часто использует:

  • Функциональное программирование
  • Прототипное наследование
  • Composition вместо наследования

Вывод: ООП и SOLID принципы — это фундамент профессиональной разработки. Даже если не используешь классы каждый день, понимание этих принципов делает код чище, maintainable и scalable. Главное — применять их разумно, не переусложняя код.

Какие знаешь принципы объектно-ориентированного программирования? | PrepBro