Ответ
Композицию следует предпочитать наследованию в большинстве случаев, так как она обеспечивает большую гибкость, слабую связанность (low coupling) и более понятную структуру кода. Этот принцип часто формулируют как "composition over inheritance".
Наследование (отношение "is-a")
Наследование создает жесткую иерархическую связь. Дочерний класс является разновидностью родительского. Это полезно, когда существует четкая таксономия, но может привести к хрупкости базового класса, когда изменения в родителе ломают потомков.
# Неправильное использование наследования
class Engine:
def start(self):
print("Engine started")
# Ошибка: Car "is-a" Engine (Машина - это двигатель) - неверно.
class Car(Engine):
pass
Композиция (отношение "has-a")
Композиция позволяет объекту содержать другие объекты. Класс имеет или использует функциональность другого класса, не становясь его подтипом. Это делает систему более модульной и упрощает замену компонентов.
# Правильное использование композиции
class Engine:
def start(self):
print("Engine started")
# Верно: Car "has-a" Engine (У машины есть двигатель).
class Car:
def __init__(self):
self.engine = Engine()
def start(self):
print("Starting the car...")
self.engine.start()
Ключевые преимущества композиции:
- Гибкость: Компоненты можно заменять во время выполнения.
- Слабая связанность: Изменения в компоненте не затрагивают класс-контейнер, если его интерфейс остается прежним.
- Простота тестирования: Каждый класс можно тестировать изолированно.