Проблема: повторяющийся код
Рассмотрим классы «Прямоугольник» и «Круг». У обоих есть цвет, который задаётся тремя числами (R, G, B):
Код работает, но три свойства цвета повторяются в каждом классе. Это неудобно и нарушает принцип DRY (Don't Repeat Yourself — «не повторяйся»).
Если захочется добавить цвету ещё одно свойство (например, прозрачность), придётся менять каждый класс по отдельности.
Решение: композиция
Композиция — это принцип, при котором один класс содержит внутри себя объекты других классов. Вместо того чтобы хранить три числа цвета, создадим отдельный класс Color и будем использовать его внутри Rectangle и Circle.
Код стал более экономным и упорядоченным. А класс Color можно использовать для любых фигур — треугольника, эллипса, многоугольника и т.д.
Как это работает
Объект rect содержит внутри себя объект color. Чтобы обратиться к красной компоненте цвета прямоугольника, нужно написать:
То есть: у прямоугольника (rect) есть цвет (color), а у цвета — красная компонента (r).
Это напоминает матрёшку: один объект вложен в другой.
Преимущества композиции
- Переиспользование кода — класс
Colorможно использовать в любом месте проекта. - Упрощение изменений — если нужно добавить цвету прозрачность, достаточно изменить только класс
Color. - Читаемость —
rect.color.rчитается естественно: «у прямоугольника цвет, у цвета красная компонента». - Логическая структура — объекты собираются из более мелких, отражая реальное устройство вещей.
Композиция в реальном мире
Композиция постоянно встречается в реальном программировании:
- Автомобиль имеет двигатель, колёса, руль. Колёса имеют диаметр, ширину профиля и тип резины.
- Дом имеет комнаты, двери, окна. Окна имеют ширину, высоту и материал.
- Заказ в интернет-магазине имеет покупателя, список товаров, адрес доставки. Покупатель имеет логин, пароль и аватарку.
Композиция помогает моделировать эти отношения «имеет» (has-a) прямо в коде.
Важное отличие: композиция vs наследование
В этом уроке мы строим сложные объекты из простых — это композиция. В следующем уроке мы рассмотрим наследование — когда один класс является частным случаем другого.
- Композиция: «Круг имеет цвет» (has-a).
- Наследование: «Собака является животным» (is-a).
Оба подхода важны и используются в разных ситуациях.