Урок 148. Агрегация

  Юрий Ворон  | 

    | 

  Обновлено 9 Июн 2018  | 

 2053

 ǀ   2 

В уроке о композиции мы говорили, что композиция объекта — это процесс создания сложных объектов из более простых. Мы также говорили об подтипе композиции объектов — композиции. В отношениях в композиции целое (класс) несет ответственность за существование частей (членов).

В этом уроке мы рассмотрим второй подтип композиции объекта – агрегацию.

Агрегация

Для реализации агрегации целое и его части должны соответствовать следующим отношениям:

  часть (член) является частью целого (класса);



  часть (член) может принадлежать более чем одному целому (классу) за раз;

  часть (член) существует, не управляемая целым (классом);

  часть (член) не знает о существовании целого (класса).

Как и в случае с подтипом композиция, отношения в агрегации также является отношениями части-целого и однонаправленные. Однако, в отличие от композиции, части могут принадлежать более чем одному целому за раз, и целое не управляет существованием и временем жизни частей. При создании/уничтожении агрегации, целое не несет ответственности за создание/уничтожение своих частей.

Например, рассмотрим отношения между человеком и его домашним адресом. У каждого человека есть свой адрес. Однако этот адрес может принадлежать более чем одному человеку за раз: например, вам и вашему соседу по комнате или родственникам, которые живут вместе с вами. Однако этот адрес не управляется человеком — адрес существовал до того, как человек заселился и будет существовать после того, как человек выселиться. Кроме того, человек знает, по какому адресу он живет, но адрес, в свою очередь, не знает, что это за человек и вообще, сколько их там живет. Такие отношения и являются агрегацией.

В качестве альтернативы, рассмотрим автомобиль и двигатель. Двигатель является частью автомобиля. И хотя двигатель принадлежит автомобилю, он может принадлежать и другим объектам, например, человеку, которому принадлежит автомобиль. Автомобиль не несет ответственности за создание или уничтожение двигателя. И в то же время автомобиль знает, что у него есть двигатель (ведь благодаря ему он двигается), но сам двигатель не знает, что он является частью автомобиля.

Когда дело доходит до моделирования физических объектов, использование термина «уничтожение» может быть немного расплывчатым. Один может утверждать: «Если бы метеорит упал с неба и раздавил машину, то можно ли считать, что и все части машины также были бы уничтожены?» Да, конечно. Но это вина метеорита, а не автомобиля. Важным моментом является то, что автомобиль не несет ответственности за уничтожение своих частей (но есть и внешняя сила, которая может этому способствовать).

Мы можем сказать, что типом отношений в агрегации является «имеет» (отдел «имеет» работников, автомобиль «имеет» двигатель).

Подобно композиции, части агрегации могут быть сингулярными или мультипликативными.

Реализация агрегации

Поскольку агрегации подобны композициям, так как оба состоят из отношений части-целого, они реализуются почти одинаково, а разница между ними в основном семантическая. В композиции мы добавляем части к целому, используя обычные переменные-члены (или указатели, когда в классе происходит динамическое выделение/освобождение памяти).

В агрегации мы также добавляем части к целому, используя переменные-члены. Однако этими переменными-членами обычно являются либо ссылки, либо указатели, которые указывают на объекты, созданные за пределами класса. Следовательно, агрегация принимает части, на которые она будет указывать, в качестве параметров конструктора или, если параметров нет, части добавляются позже через функции доступа или через перегруженные операторы.

Поскольку эти части существуют вне области видимости класса, то при уничтожении класса, переменные-члены в виде ссылок или указателей также уничтожаются (но не удаляются значения, на которые они указывают). Следовательно, сами части продолжают существовать дальше.



Рассмотрим пример Работника и Отдела более подробно. Чтобы было проще, в Отделе работает только один Работник и он не знает, Работником какого именно Отдела он является.

Здесь Работник создается независимо от Отдела, а затем переходит в параметр конструктора класса Отдела. Когда department уничтожается, указатель m_worker уничтожается также, но сам Работник то не удаляется, он существует и дальше до тех пор, пока не будет уничтожен в main().

Выбирайте правильные отношения

Хотя в примере выше может показаться немного глупым, что Работник не знает, в каком Отделе он работает, это может быть совершенно нормальным в контексте данной программы. Когда вы определяете тип отношений для реализации, внедряйте самые простые и понятные отношения, которые соответствуют вашим потребностям, а не те, которые, как вам кажется, подойдут лучше всего, но они сложнее и навороченнее.

Например, если вы создаете симулятор ремонтной автомобилей, вы можете захотеть реализовать автомобиль и двигатель через агрегацию, чтобы двигатель можно было вынуть и отдельно в нем разобраться. Однако, если вы пишете гоночный симулятор, вы можете захотеть реализовать автомобиль и двигатель через композицию, поскольку в гонке двигателю существовать отдельно от автомобиля никак нельзя.

Правило: Реализовывайте самые простые отношения, которые соответствует потребностям вашей программы, а не то, что, как вам кажется, будет лучшим.

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

Композиция:

  используются обычные переменные-члены;

  используются указатели, если класс реализовывает собственное управление памятью (происходит динамическое выделение/освобождение памяти);

  класс ответственный за создание/уничтожение своих частей.

Агрегация:

  используются указатели/ссылки, которые указывают/ссылаются на части вне класса;

  класс не несет ответственности за создание/уничтожение своих частей.

Стоит отметить, что идеи композиции и агрегации не являются взаимоисключающими и могут свободно смешиваться в одном классе. Вполне возможно реализовать класс, который отвечает за создание/уничтожение только определенных частей. Например, наш класс Department мог бы иметь и Имя, и Работника. Имя было бы добавлено в класс через композицию и создавалось/уничтожалось бы вместе с объектами класса Department. А Работник был бы добавлен в Department через агрегацию и создавался/уничтожался бы независимо/отдельно.

Хотя агрегации могут быть чрезвычайно полезными, они также потенциально опасны. Поскольку в агрегации автоматически не осуществляется освобождение памяти, которую могут занимать части, то это должны контролировать вы. Если вы забыли выполнить очистку (освободить память), думая, что это должен сделать класс, то тогда произойдет утечка памяти. Поэтому следует быть осторожным.

Примечание: По разным историческим и другим причинам, в отличие от композиции, определение агрегации не является единственно правильным — вы можете увидеть, что другие ресурсы/сайты/учебники определяют агрегацию несколько иначе, нежели изложено здесь. Это нормально, просто знайте об этом.

Тест

Задание №1

Для реализации следующего вы бы использовали агрегацию или композицию?

  Красный шар

  Работодатель, который нанимает людей

  Факультет в университете

  Ваш возраст

  Мешок с шариками

Ответ 1

  Композиция: Цвет является неотъемлемым свойством шара.

  Агрегация: Работодатель в начале не имеет никаких работников и, надеемся, не уничтожит всех своих сотрудников, когда обанкротится.

  Композиция: Факультеты не могут существовать отдельно от университета.

  Композиция: Ваш возраст является неотъемлемым свойством Вас.

  Агрегация: Мешок и шарики внутри являются независимыми объектами и могут существовать раздельно.

Задание №2

Обновите пример выше с Работником/Отделом, чтобы Отдел мог состоять из нескольких Работников. Следующий код:

должен производить следующий результат:

Department: Anton Ivan Max
Anton still exists!
Ivan still exists!
Max still exists!

Подсказка: Используйте std::vector для хранения Работников. Используйте std::vector::push_back() для добавления Работника. Используйте std::vector::size() для получения длины std::vector для вывода.

Ответ 2

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (16 оценок, среднее: 4,94 из 5)
Загрузка...

Комментариев: 2

  1. Игорь:

    Всем привет.Моё решение:

  2. Anastasia:

    Для вывода вектора необязательно использовать size:

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *