User Professor Hans Noodles
Professor Hans Noodles
41 уровень

Отношения между классами. Наследование, композиция и агрегирование

Статья из группы Java Developer
Привет! Сегодня мы подробно рассмотрим еще один принцип объектно-ориентированного программирования (ООП) — наследование. Заодно изучим другие типы отношений между классами — композицию и агрегирование.
Отношения между классами. Наследование, композиция и агрегирование  - 1
Эта тема не будет сложной: ты уже много раз сталкивался с наследованием и его примерами в прошлых лекциях. Сегодня главным будет закрепить твои знания, подробнее рассмотреть механизм наследования и еще раз пробежаться по примерам :) Итак, поехали!

Наследование в Java и его преимущества

Как ты наверняка помнишь, наследование (inheritance) — механизм, который позволяет описать новый класс на основе существующего (родительского). При этом свойства и функциональность родительского класса заимствуются новым классом. Давай вспомним пример наследования из предыдущих лекций:

public class Car {

   private String model;
   private int maxSpeed;
   private int yearOfManufacture;

   public Car(String model, int maxSpeed, int yearOfManufacture) {
       this.model = model;
       this.maxSpeed = maxSpeed;
       this.yearOfManufacture = yearOfManufacture;
   }


public void gas() {
       //...газ
   }

public void brake() {
       //...тормоз
   }
}


public class Truck extends Car {

   public Truck(String model, int maxSpeed, int yearOfManufacture) {
       super(model, maxSpeed, yearOfManufacture);
   }
}



public class Sedan extends Car {
   public Sedan(String model, int maxSpeed, int yearOfManufacture) {
       super(model, maxSpeed, yearOfManufacture);
   }
}
Есть некая программа, в рамках которой мы работаем с различными типами автомобилей. Даже если ты не автолюбитель, наверняка знаешь, что типов этих самых автомобилей на свете великое множество :) Поэтому общие свойства автомобилей выделяем в общий класс-родитель — Car. А что общего у всех автомобилей вне зависимости от типа? У любой машины есть год выпуска, название модели и максимальная скорость. Эти свойства выносим в поля model, maxSpeed, yearOfManufacture. Что касается поведения, любая машина может газовать и тормозить :) Это поведение мы определяем в методах gas() и brake(). Какие выгоды это нам дает? Прежде всего — сокращение объема кода. Конечно, можем обойтись и без родительского класса. Но поскольку каждая машина должна уметь газовать и тормозить, нам придется создавать методы gas() и brake() в классе Truck, в классе Sedan, в классе F1Car, в классе Sportcar и во всех остальных классах машин. Представь, сколько лишнего кода мы при этом напишем. Не забывай и о полях model, maxSpeed и yearOfManufacture: если откажемся от родительского класса, будем создавать их в каждом из классов-машин! Отношения между классами. Наследование, композиция и агрегирование  - 2 Когда у нас наберется пара десятков классов-машин, объем повторяющегося кода станет действительно серьезным. Вынесение общих полей и методов (еще говорят — «состояния» и «поведения») в класс-родитель позволит нам сэкономить кучу времени и места. Если же у какого-то типа есть свойства или методы, уникальные только для него и отсутствующие у других типов машин, — не беда. Их всегда можно создать в классе-потомке, отдельно от всех остальных.

public class F1Car extends Car {

   public void pitStop() {
      
       //...пит-стоп делают только гоночные автомобили
   }

   public static void main(String[] args) {
      
       F1Car formula1Car = new F1Car();
       formula1Car.gas();
       formula1Car.pitStop();
       formula1Car.brake();
   }
}
Возьмем случай с гоночными машинами Формулы-1. У них, в отличие от «сородичей», есть уникальное поведение — время от времени они заезжают на пит-стоп. Нам это не мешает. Общее поведение мы уже описали в родительском классе Car, а специфическое поведение классов-потомков можем добавить внутри классов. Отношения между классами. Наследование, композиция и агрегирование  - 3 Это касается и полей: если у дочернего класса есть уникальные свойства, спокойно объявляем эти поля внутри него и не переживаем :) Возможность повторного использования кода — главное преимущество наследования. Для программиста очень важно не писать лишний объем кода. Ты не раз столкнешься с этим в работе. Пожалуйста, запомни еще одну крайне важную вещь: в Java нет множественного наследования. Каждый класс наследуется только от одного класса. О причинах этого подробнее поговорим в будущих лекциях, пока просто запомни. Этим Java, кстати, отличается от некоторых других ООП-языков. Например, в С++ множественное наследование есть. С наследованием все более-менее ясно — идем дальше.

Композиция и агрегирование

Классы и объекты могут быть связаны друг с другом. Наследование описывает связь «является» (или по-английски «IS A»). Лев является Животным. Такое отношение легко выразить с помощью наследования, где Animal будет родительским классом, а Lion — потомком. Однако не все связи отношения в мире описываются таким образом. К примеру, клавиатура определенно как-то связана с компьютером, но она не является компьютером. Руки как-то связаны с человеком, но они не являются человеком. В этих случаях в его основе лежит другой тип отношения: не «является», а «является частью» («HAS A»). Рука не является человеком, но является частью человека. Клавиатура не является компьютером, но является частью компьютера. Отношения HAS A можно описать в коде, используя механизмы композиции и агрегирования. Разница между ними заключается в «строгости» этих связей. Приведем простой пример: У нас есть наш Car — машина. У каждой машины есть двигатель. Кроме того, у каждой машины есть пассажиры внутри. В чем же принципиальная разница между полями Engine engine и Passenger [] passengers? Если у машины внутри сидит пассажир А, это не значит, что в ней не могут находиться пассажиры B и C. Одна машина может соответствовать нескольким пассажирам. Кроме того, если всех пассажиров высадить из машины, она продолжит спокойно функционировать. Связь между классом Car и массивом пассажиров Passenger [] passengers менее строгая. Она называется агрегацией. Есть неплохая статья на эту тему: Отношения между классами (объектами). В ней приведен еще один хороший пример агрегации. Допустим, у нас есть класс Student, обозначающий студента, и класс StudentsGroup (группа студентов). Студент может входить и в клуб любителей физики, и в студенческий фан-клуб «Звездных войн» или команду КВН. Композиция — более строгий тип связи. При использовании композиции объект не только является частью какого-то объекта, но и не может принадлежать другому объекту того же типа. Самый простой пример — двигатель автомобиля. Двигатель является частью автомобиля, но не может быть частью другого автомобиля. Как видишь, их связь гораздо более строгая, чем у Car и Passengers. Отношения между классами. Наследование, композиция и агрегирование  - 4
Комментарии (149)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Денис Викторович Уровень 11, Краснодар
25 апреля 2022
Классная статья!) Благодарю))
Chestorr Уровень 21, Москва, Russian Federation
17 апреля 2022
Хорошее видео, объясняющее как применять принципы "is a" и "has a", и разницу между ними: https://www.youtube.com/watch?v=pZg4-qYzSWU&ab_channel=%D0%A3%D1%80%D0%BE%D0%BA%D0%B8Java
Валера Калиновский Уровень 32, Харьков, Украина
7 апреля 2022
нет кода по композиции и агрегации. хотя есть ссылка где он есть. Спасибо
Рогов Игорь Уровень 39, Самара, Russian Federation
16 февраля 2022
тема не раскрыта. объявили что есть композиция и агрегация, а что из этого вытекает не рассказали. для чего выделили эти состояния ? и в чем их уникальность то?
Anonymous #2903643 Уровень 27, Russian Federation
20 декабря 2021
Двоечники! Газовать и тормозить может водитель. А машина может только ускорятся и замедляться. :)
Aleksei Reinsalu Уровень 19, Таллинн, Эстония
28 ноября 2021
Провел маленькое расследование значения слов. У этих слов есть и другие значения.. выбрал самые полезные для укладывания лекции в голову. Слово Ассоциация означает Связь. Любая Связь между классами это Ассоциация. Слово Агрегация означает Скопление. Агрегирование это частный случай Ассоциации, когда Связи с одним или больше объектами первого класса могут Скапливаться внутри единственного объекта второго класса. Слово Композиция означает Сплав (неразделимое соединение) Композиция это частный случай Агрегирования, когда уничтожение объекта первого класса автоматически стирает все объекты второго класса, Связи с которыми в нем Скопились.
Валентин Еременко Уровень 23, Волгодонск, Россия
18 ноября 2021
Поправьте, если ошибаюсь: в лекции говорилось о том, что композиция - это принадлежность объекта только к одному объекту(движок может быть двигателем только этой машины и никак не другой), а на картинке немного другая ситуация описана.
newNoName Уровень 28, Киев, Ukraine
8 ноября 2021

Есть неплохая статья на эту тему: Отношения между классами (объектами).
сайт - Not Secure - (не защищён, переведу) - автор, зачем ссылки на недо-сайты кидаешь? у меня ноут берут иногда дети и я не хочу чтобы им выскочила реклама - "увеличь на 20 см"
Grustnij Los' Уровень 28, Санкт-Петербург, Russian Federation
5 ноября 2021
Большущая благодарность автору за информацию по теме "Наследование, композиция и агрегирование", но даже прочитав доп. статью тема не раскрылась. Непонятно, как это реализуется и в каких случаях может быть использовано. Если есть возможность прояснить, буду признателен.
Sergey Kornilov Уровень 38, Petropavlovsk, Казахстан
20 октября 2021
В закладки.