Что такое ООП: четыре принципа с примерами кода
Основы3 минРедакция Innovialabs
Коротко
ООП — способ строить программу из объектов, которые объединяют данные и поведение; четыре принципа (инкапсуляция, наследование, полиморфизм, абстракция) помогают прятать детали и заменять одни реализации другими.
Коротко: что такое ООП
Объектно-ориентированное программирование (ООП) — подход, при котором программа состоит из объектов: каждый объект хранит свои данные (поля) и умеет с ними работать (методы). Шаблон объекта называется классом.
Смысл ООП не в классах самих по себе, а в том, чтобы разделить систему на части с понятными границами: снаружи видно, что объект умеет, а как он это делает — его внутреннее дело.
Ниже все четыре принципа показаны на одном примере: сервис отправляет уведомления по 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-шлюза.
Где ООП используют лишнее
- Глубокие иерархии наследования. Пять уровней классов сложно понимать и менять. Чаще лучше композиция: объект содержит другой объект, а не наследуется от него.
- Классы ради классов. Если у класса один метод и нет состояния, обычная функция проще.
- Анемичные модели. Классы только с геттерами и сеттерами без поведения дают оверхед ООП без его пользы.
- Обработка данных. Преобразования списков, отчёты и пайплайны часто читаются лучше в функциональном стиле.
- Абстракции «на будущее». Интерфейс с единственной реализацией и без планов на вторую усложняет код уже сейчас.
Хорошее правило: вводите абстракцию, когда у вас появилась вторая реальная реализация или нужна подмена в тестах.