Что такое SOLID
SOLID — это акроним пяти принципов объектно-ориентированного проектирования, сформулированных Робертом Мартином. Эти принципы помогают создавать гибкие, поддерживаемые и масштабируемые системы, снижая связанность и повышая устойчивость к изменениям. Каждый принцип решает конкретную проблему проектирования, а их совместное применение позволяет строить архитектуру, которую легко расширять и тестировать.
Как расшифровывается SOLID
-
S — Single Responsibility (Принцип единственной ответственности)
Каждый класс должен отвечать только за одну операцию или иметь одну причину для изменения. Это упрощает понимание кода, тестирование и снижает риск побочных эффектов при модификациях. -
O — Open-Closed (Принцип открытости-закрытости)
Классы должны быть открыты для расширения, но закрыты для модификации. То есть новое поведение добавляется через наследование или композицию, а не изменением существующего кода. -
L — Liskov Substitution (Принцип подстановки Барбары Лисков)
Если классSявляется подтипомT, то объекты типаTмогут быть заменены объектами типаSбез нарушения работы программы. Это гарантирует корректность наследования и полиморфизма. -
I — Interface Segregation (Принцип разделения интерфейсов)
Клиент не должен зависеть от методов, которые он не использует. Лучше иметь несколько узких интерфейсов, чем один широкий. -
D — Dependency Inversion (Принцип инверсии зависимостей)
Модули верхнего уровня не должны зависеть от модулей нижнего уровня; оба должны зависеть от абстракций. Абстракции не должны зависеть от деталей; детали должны зависеть от абстракций.
Примеры на Python
S — нарушение и исправление
# Нарушение: класс делает две вещи — хранит данные и сохраняет их в БД
class User:
def __init__(self, name):
self.name = name
def save_to_db(self):
# логика сохранения
pass
# Исправление: разделяем ответственность
class User:
def __init__(self, name):
self.name = name
class UserRepository:
def save(self, user):
# логика сохранения
passO — расширение без модификации
class Shape:
def area(self):
raise NotImplementedError
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
# Добавляем новую фигуру, не трогая существующий код
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2L — подстановка
class Bird:
def fly(self):
return "Летит"
class Penguin(Bird):
def fly(self):
raise Exception("Пингвин не летает")
# Нарушение: Penguin не может заменить Bird без ошибок
# Исправление: выделить интерфейс FlyingBirdI — разделение интерфейсов
# Нарушение: широкий интерфейс
class Worker:
def work(self):
pass
def eat(self):
pass
# Исправление: узкие интерфейсы
class Workable:
def work(self):
pass
class Eatable:
def eat(self):
passD — инверсия зависимостей
# Нарушение: высокоуровневый модуль зависит от конкретной реализации
class EmailSender:
def send(self, message):
pass
class NotificationService:
def __init__(self):
self.sender = EmailSender() # жёсткая связь
# Исправление: зависимость от абстракции
class MessageSender:
def send(self, message):
pass
class EmailSender(MessageSender):
def send(self, message):
pass
class NotificationService:
def __init__(self, sender: MessageSender):
self.sender = sender # внедрение зависимостиПодводные камни и частые ошибки
- Слепое следование принципам: иногда излишнее разбиение на классы усложняет код. Применяйте принципы осознанно, учитывая контекст.
- Нарушение LSP: часто встречается, когда наследник изменяет поведение базового класса неожиданным образом (например, выбрасывает исключения).
- Интерфейсы в Python: в Python нет явных интерфейсов, но их роль выполняют абстрактные базовые классы (ABC) или протоколы.
- Инверсия зависимостей: не путать с внедрением зависимостей (DI) — DI является одним из способов реализации этого принципа.
Когда использовать SOLID
Принципы SOLID полезны при проектировании средних и крупных систем, где важна поддерживаемость и расширяемость. Для небольших скриптов они могут быть избыточны, но понимание этих принципов помогает писать более чистый код в любом масштабе.
Коротко
- SOLID — пять принципов ООП: единственная ответственность, открытость-закрытость, подстановка Лисков, разделение интерфейсов, инверсия зависимостей.
- Каждый принцип снижает связанность и упрощает изменение кода.
- В Python принципы реализуются через классы, наследование, абстрактные классы и композицию.
- На собеседовании ожидайте не только перечисление, но и примеры нарушения и исправления.
