Урок №156. Агрегація

  Юрій  | 

  Оновл. 19 Лют 2021  | 

 52

На уроці про композицію ми говорили, що композиція об’єкта — це процес створення складних об’єктів з простих. Ми також говорили про підтип композиції об’єктів — композицію. У відносинах всередині композиції ціле (клас) несе відповідальність за існування частин (членів).

На цьому уроці ми розглянемо інший підтип композиції об’єкта — агрегацію.

Агрегація

Для реалізації агрегації ціле і його частини повинні відповідати наступним відносинам:

   Частина (член) є частиною цілого (класу).

   Частина (член) може належати більш ніж одному цілому (класу) за раз.

   Частина (член) існує, НЕ керована цілим (класом).

   Частина (член) не знає про існування цілого (класу).

Як і у випадку з підтипом композиція, відносини в агрегації також є відносинами “частин-цілого” і односпрямовані. Однак, на відміну від композиції, частини можуть належати більш ніж одному цілому за раз, і ціле не керує існуванням і тривалістю життя частин. При створенні/знищенні агрегації, ціле не несе відповідальності за створення/знищення своїх частин.

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

В якості альтернативи розглянемо автомобіль і двигун. Двигун є частиною автомобіля. І хоча двигун належить автомобілю, він може належати і іншим об’єктам, наприклад, людині, якій належить автомобіль. Автомобіль не несе відповідальності за створення або знищення двигуна. І в той же час автомобіль знає, що у нього є двигун (адже завдяки йому він рухається), але сам двигун не знає, що він є частиною автомобіля.

Коли справа заходить до моделювання фізичних об’єктів, використання терміну «знищення» може бути трохи розпливчатим. Виникає питання: «Якби метеорит впав з неба і розчавив машину, то чи можна було б вважати, що і всі частини машини також знищені?». Так, звичайно. Але це вина метеорита, а не автомобіля. Важливим моментом є те, що автомобіль не несе відповідальності за знищення своїх частин (але є і зовнішня сила, яка може цьому посприяти).

Ми можемо сказати, що типом відносин в агрегації є «має» (відділ «має» працівників, автомобіль «має» двигун).

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

Реалізація агрегації

Оскільки агрегація подібна композиції, так як обидві складаються з відносин “частин-цілого”, то вони реалізуються майже однаково, а різниця між ними в основному семантична. У композиції ми додаємо частини до цілого, використовуючи звичайні змінні-члени (або вказівники, коли в класі відбувається динамічне виділення/звільнення пам’яті).

В агрегації ми також додаємо частини до цілого, використовуючи змінні-члени. Однак цими змінними-членами зазвичай є або посилання, або вказівники, які вказують на об’єкти, створені за межами класу. Отже, агрегація приймає частини, на які вона вказуватиме, в якості параметрів конструктора або, якщо параметрів немає, частини додаються пізніше через функції доступу або через перевантажені оператори.

Оскільки ці частини існують поза областю видимості класу, то при знищенні класу, змінні-члени у вигляді посилань або вказівників також знищуються (але не знищуються значення, на які вони вказують). Відповідно, самі частини продовжують своє існування.

Розглянемо приклад Працівника і Відділу детально. Щоб було простіше, в Відділі працює тільки один Працівник і він не знає, Працівником якого саме Відділу він є:

Тут Працівник створюється незалежно від Відділу, а потім переходить в параметр конструктора класу Відділ. Коли 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 Зірок (1 оцінок, середня: 5,00 з 5)
Loading...

Залишити відповідь

Ваш E-mail не буде опублікований. Обов'язкові поля відмічені *