Какие существуют ключевые принципы объектно-ориентированного проектирования?

Ответ

Для создания гибких, масштабируемых и поддерживаемых систем в ООП используются проверенные временем принципы. Наиболее известными являются SOLID.

Принципы SOLID

Это акроним, обозначающий пять основных принципов:

  • S - Single Responsibility Principle (Принцип единственной ответственности) Класс должен иметь только одну причину для изменения. Это значит, что он должен решать одну четко определенную задачу.

  • O - Open/Closed Principle (Принцип открытости/закрытости) Программные сущности (классы, модули) должны быть открыты для расширения, но закрыты для модификации.

  • L - Liskov Substitution Principle (Принцип подстановки Барбары Лисков) Объекты в программе должны быть заменяемы на экземпляры их подтипов без изменения правильности выполнения программы.

  • I - Interface Segregation Principle (Принцип разделения интерфейса) Много специализированных интерфейсов лучше, чем один универсальный. Клиенты не должны зависеть от методов, которые они не используют.

  • D - Dependency Inversion Principle (Принцип инверсии зависимостей) Модули верхних уровней не должны зависеть от модулей нижних уровней. И те, и другие должны зависеть от абстракций.

Пример нарушения и исправления SRP

# ПЛОХО: Класс User отвечает и за данные, и за их сохранение
class User:
    def __init__(self, name):
        self.name = name

    def save_to_db(self):
        # ... логика подключения к БД и сохранения ...
        print(f"Пользователь {self.name} сохранен в БД.")

# ХОРОШО: Ответственности разделены
class User:
    def __init__(self, name):
        self.name = name

class UserRepository:
    def save(self, user: User):
        # ... логика подключения к БД и сохранения ...
        print(f"Пользователь {user.name} сохранен в БД.")

Другие важные принципы

  • DRY (Don't Repeat Yourself): Избегайте дублирования кода.
  • KISS (Keep It Simple, Stupid): Предпочитайте простые решения сложным.
  • Composition over Inheritance (Композиция вместо наследования): Отдавайте предпочтение построению сложных объектов из более простых, а не наследованию от них. Это обеспечивает большую гибкость.

Ответ 18+ 🔞

Так, слушай, смотри, есть эта ваша ООП, да? А чтобы в ней не наделать таких дел, что потом самому разгребать овердохуища, умные дядьки придумали принципы. Самые главные — SOLID, ну, как пять заповедей, только для кода, без всякой этой духовности, чистая механика, блядь.

SOLID — это не про твёрдое тело, а про то, чтобы твой код не был жидким говном, которое растекается при первой же правке.

  • S — Единственная ответственность (Single Responsibility). Это ж элементарно, Ватсон! Один класс — одна работа. Не надо делать из него швейцарский нож, который и пользователя создаёт, и в базу его пихает, и письма шлёт, и чай заваривает. Ёпта, он же с ума сойдёт, бедный! Как и ты, когда его менять начнёшь.
  • O — Открыт для расширения, закрыт для изменений (Open/Closed). Представь: у тебя рабочий модуль. Чтобы добавить новую фичу, его не надо вскрывать, как консервную банку, и ковыряться в потрохах. Ты должен иметь возможность прикрутить новое поведение сбоку, через новые классы, а старый код оставить в покое, блядь. Идеал, конечно, но к нему надо стремиться.
  • L — Подстановка Лисков (Liskov Substitution). Ну, тут история. Если у тебя есть, условно, класс Утка, и от него наследуется РезиноваяУтка, то везде, где в коде ждали Утку, должна спокойно работать и РезиноваяУтка. А если твоя резиновая утка вместо «кря-кря» вдруг начинает стрелять лазером из глаз или, того хуже, не умеет плавать — это пиздец, принцип нарушен. Наследник не должен ломать логику предка, иначе зачем он вообще нужен?
  • I — Разделение интерфейса (Interface Segregation). Не делай один интерфейс на все случаи жизни, от которого у клиентов будет болеть жопа. Лучше десять маленьких и точных. Смотри: если у тебя есть интерфейс УмноеУстройство с методами звонить(), отправлятьСМС(), показыватьПогоду() и измерятьРадиацию(), то старый кнопочный телефон, который его реализует, будет вынужден иметь пустые заглушки для половины методов. Это идиотизм. Раздели на Телефон и МетеостанцияСДозиметром.
  • D — Инверсия зависимостей (Dependency Inversion). Высокоуровневые модули (твоя бизнес-логика) не должны ползать на коленях перед низкоуровневыми (работа с базой, файлами, сетью). И те, и другие должны зависеть от абстракций (интерфейсов). Проще говоря, твой сервис не должен знать, что там у тебя MySQL или MongoDB. Он знает только интерфейс Хранилище с методом сохранить(). А ты ему подсовываешь нужную реализацию. Гибко, заменяемо, красиво. Не как у некоторых.

Вот, смотри, как можно наступить на грабли с первым принципом и как этого избежать:

# ПЛОХО: Класс-мутант. Он и пользователь, и дворник, и сантехник.
class User:
    def __init__(self, name):
        self.name = name

    def save_to_db(self): # О, бля, а это тут откуда? Он что, ещё и базу знает?
        # ... логика подключения к БД и сохранения ...
        print(f"Пользователь {self.name} сохранен в БД.")

# ХОРОШО: Всё по полочкам. Каждый занят своим делом, как в хорошем колхозе.
class User: # Этот чувак — просто данные. Имя, возраст, хобби. И всё.
    def __init__(self, name):
        self.name = name

class UserRepository: # А этот ушлый тип знает, где и как эти данные припрятать.
    def save(self, user: User):
        # ... логика подключения к БД и сохранения ...
        print(f"Пользователь {user.name} сохранен в БД.")

Ну и ещё парочка принципов, без которых — никуда:

  • DRY (Don't Repeat Yourself). Не повторяйся, ёпта! Скопировал код два раза — уже пора выносить в функцию или класс. Иначе потом будешь как дурак править одно и то же в десяти местах.
  • KISS (Keep It Simple, Stupid). Делай проще, тупица! (Это не оскорбление, это принцип такой). Не выёбывайся с навороченными паттернами там, где можно решить задачу парой прямых действий.
  • Composition over Inheritance. Композиция вместо наследования. Это, блядь, очень важно. Не лезь в глубокое наследование, как в омут. Чаще лучше собрать объект, как конструктор, из маленьких независимых частей. Наследование — жёсткая связь, а композиция даёт свободу манёвра, в рот меня чих-пых! Хочешь сменить поведение — просто замени одну деталь на другую.