Ответ
Композиция в объектно-ориентированном программировании (ООП) — это принцип, при котором один объект (целое) содержит ссылки на другие объекты (части), формируя отношение "имеет" (has-a). Это позволяет создавать сложные объекты из более простых, делегируя им часть функциональности.
Почему композиция важна? В отличие от наследования ("является" - is-a), композиция способствует слабой связанности (loose coupling) и высокой связности (high cohesion), что делает код более гибким, модульным и легким для тестирования и поддержки. Она позволяет избежать проблем, связанных с жесткой иерархией наследования и множественным наследованием.
Пример реализации на Python:
Представим, что автомобиль Car
"имеет" двигатель Engine
.
class Engine:
def __init__(self, horsepower: int):
self.horsepower = horsepower
print(f"Двигатель мощностью {self.horsepower} л.с. создан.")
def start(self) -> str:
return "Двигатель запущен."
def stop(self) -> str:
return "Двигатель остановлен."
class Car:
def __init__(self, make: str, model: str, engine_hp: int):
self.make = make
self.model = model
self.engine = Engine(engine_hp) # Композиция: Car содержит Engine
def start_car(self) -> str:
return f"{self.make} {self.model}: {self.engine.start()}"
def stop_car(self) -> str:
return f"{self.make} {self.model}: {self.engine.stop()}"
def get_info(self) -> str:
return f"Автомобиль: {self.make} {self.model}, Мощность двигателя: {self.engine.horsepower} л.с."
# Использование композиции
my_car = Car("Toyota", "Camry", 180)
print(my_car.get_info())
print(my_car.start_car())
print(my_car.stop_car())
В этом примере класс Car
не наследует от Engine
, а содержит его экземпляр. Car
делегирует операции запуска и остановки своему объекту engine
.
Преимущества композиции:
- Гибкость: Можно легко заменить тип двигателя (например, на электрический) без изменения логики класса
Car
, если новый двигатель реализует тот же интерфейс. - Снижение связанности: Изменения в
Engine
минимально влияют наCar
, если публичный интерфейсEngine
остается стабильным. - Повторное использование:
Engine
может быть использован в других классах (например,Boat
,Generator
) без необходимости наследования. - Избегание проблем наследования: Нет проблем с "алмазным" наследованием или нежелательным наследованием методов.