Перейти к содержанию
Innovialabs

Что такое ООП: четыре принципа с примерами кода

Основы3 мин

Коротко

ООП — способ строить программу из объектов, которые объединяют данные и поведение; четыре принципа (инкапсуляция, наследование, полиморфизм, абстракция) помогают прятать детали и заменять одни реализации другими.

Коротко: что такое ООП

Объектно-ориентированное программирование (ООП) — подход, при котором программа состоит из объектов: каждый объект хранит свои данные (поля) и умеет с ними работать (методы). Шаблон объекта называется классом.

Смысл ООП не в классах самих по себе, а в том, чтобы разделить систему на части с понятными границами: снаружи видно, что объект умеет, а как он это делает — его внутреннее дело.

Ниже все четыре принципа показаны на одном примере: сервис отправляет уведомления по email и SMS.

Сквозной пример на Python

from abc import ABC, abstractmethod

class Notifier(ABC):
    def __init__(self, recipient: str):
        self._recipient = recipient
        self._sent = 0

    @property
    def sent(self) -> int:
        return self._sent

    def notify(self, text: str) -> None:
        self._deliver(text)
        self._sent += 1

    @abstractmethod
    def _deliver(self, text: str) -> None: ...

class EmailNotifier(Notifier):
    def _deliver(self, text: str) -> None:
        print(f"Email to {self._recipient}: {text}")

class SmsNotifier(Notifier):
    def _deliver(self, text: str) -> None:
        print(f"SMS to {self._recipient}: {text}")

for n in [EmailNotifier("user@example.com"), SmsNotifier("+998000000000")]:
    n.notify("Your order has shipped")

Тот же пример на Java

abstract class Notifier {
    private final String recipient;
    private int sent = 0;

    Notifier(String recipient) { this.recipient = recipient; }

    public int getSent() { return sent; }
    protected String recipient() { return recipient; }

    public void notify(String text) {
        deliver(text);
        sent++;
    }

    protected abstract void deliver(String text);
}

class EmailNotifier extends Notifier {
    EmailNotifier(String r) { super(r); }
    protected void deliver(String text) {
        System.out.println("Email to " + recipient() + ": " + text);
    }
}

class SmsNotifier extends Notifier {
    SmsNotifier(String r) { super(r); }
    protected void deliver(String text) {
        System.out.println("SMS to " + recipient() + ": " + text);
    }
}

Примечание: в Java у Object уже есть метод notify(), поэтому в реальном коде метод лучше назвать иначе, например send. Здесь имя оставлено одинаковым ради сравнения.

Четыре принципа на этом примере

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

Счётчик sent нельзя изменить снаружи: в Java он private, в Python — _sent с доступом только на чтение через @property. Увеличивается он только внутри notify. Инкапсуляция защищает данные от некорректных изменений и даёт одно место, где меняется состояние.

В Python приватность — соглашение (подчёркивание), а не запрет. В Java компилятор действительно не даст обратиться к private полю.

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

EmailNotifier и SmsNotifier наследуют от Notifier общую логику: хранение получателя, подсчёт отправок, метод notify. Им остаётся реализовать только свою часть — deliver.

Полиморфизм

Цикл вызывает notify у каждого объекта, не зная его конкретного класса. Один интерфейс — разное поведение. Добавить Telegram-уведомления можно новым классом, не трогая цикл и остальной код.

Абстракция

Notifier — абстрактный класс: он описывает, что делает уведомитель, и скрывает, как именно. Создать «просто Notifier» нельзя, только конкретную реализацию. Код, который отправляет уведомления, зависит от абстракции, а не от деталей SMS-шлюза.

Где ООП используют лишнее

  • Глубокие иерархии наследования. Пять уровней классов сложно понимать и менять. Чаще лучше композиция: объект содержит другой объект, а не наследуется от него.
  • Классы ради классов. Если у класса один метод и нет состояния, обычная функция проще.
  • Анемичные модели. Классы только с геттерами и сеттерами без поведения дают оверхед ООП без его пользы.
  • Обработка данных. Преобразования списков, отчёты и пайплайны часто читаются лучше в функциональном стиле.
  • Абстракции «на будущее». Интерфейс с единственной реализацией и без планов на вторую усложняет код уже сейчас.

Хорошее правило: вводите абстракцию, когда у вас появилась вторая реальная реализация или нужна подмена в тестах.

Частые вопросы

Да, в Python всё является объектом, и классы поддерживаются полностью. Но язык не заставляет писать в стиле ООП: функции и модули там такие же полноценные инструменты.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.