Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Проектування інформаційних систем.doc
Скачиваний:
95
Добавлен:
21.09.2019
Размер:
28.77 Mб
Скачать

15.4.4. Агрегація

Приклад 15.3. Відношення агрегації між класами має безпосереднє відношення до агрегації між їх екземплярами. Розглянемо знову клас TemperatureController:

class TemperatureController {

public:

TemperatureController(Location);

~TemratureController();

void process(const TemperatureRamp&);

Minute schedule(const TemperatureRamp&) const;

private:

Heater h;

};

Рис. 15.8. Агрегація.

Як видно з рис. 15.8, клас TemperatureController це, безсумнівно, ціле, а екземпляр класу Heater - одна з його частин. Таке ж відношення агрегації між екземплярами цих класів показано на рис. 15.3.

Фізичне включення. У випадку класу TemperatureController ми маємо агрегацію за значенням; цей різновид фізичного включення означає, що об'єкт класу Heater не існує окремо від екземпляра класу TemperatureController.

Менш зобов'язуючим є включення за посиланням. Ми могли б змінити закриту частину TemperatureController так:

Heater* h;

У цьому випадку клас TemperatureController як і раніше означає ціле, але його частина, екземпляр класу Heater, міститься в цілому другорядно. Тепер ці об'єкти живуть окремо один від одного: ми можемо створювати, і знищувати екземпляри класів незалежно. Щоб уникнути структурної залежності через посилання важливо дотримуватися якоїсь домовленості щодо створення й знищення об'єктів, посилання на які можуть міститися в різних місцях. Потрібно, щоб це робив хтось один.

Агрегація є направленою, як і будь-яке відношення "ціле/частина". Об'єкт Heater входить в об'єкт TemperatureController, і не навпаки. Фізичне входження одного в інший не можна "зациклити", а от показники - можна (кожний із двох об'єктів може містити показник на інший).

Агрегація не вимагає обов'язкового фізичного включення, ні за значенням, ні за посиланням. Наприклад, акціонер володіє акціями, але вони не є його фізичною частиною. Більше того, час життя цих об'єктів може бути зовсім різним, хоча концептуально відношення цілого й частини зберігається, і кожна акція входить у майно свого акціонера. Тому агрегація може бути другорядною. Наприклад, об'єкт класу Shareholder (акціонер) може містити ключ запису про цього акціонера в базі даних акцій. Це теж агрегація без фізичного включення. "Лакмусовий папірець" для виявлення агрегації такий: якщо (і тільки якщо) видно відношення "ціле/частина" між об'єктами, їх класи повинні перебувати у відношенні агрегації один з одним. 

Рис. 15.9. Відношення використання.

Часто агрегацію плутають із множинним успадкуванням. Дійсно, в C++ приховане (захищене або закрите) успадкування майже завжди можна замінити прихованою агрегацією екземпляра суперкласу. Вирішуючи, із чим ви маєте справу - зі успадкуванням чи агрегацією - будьте обережні. Якщо ви не впевнені в наявності відношення загального й частового (is_а), то замість успадкування краще застосувати агрегацію або інший вид відношення.

15.4.5. Використання

Приклад 15.4. У попередньому прикладі об'єкти rampController і growingRamp ілюстрували зв'язок між об'єктами, що ми задали у вигляді відношення використання між їх класами TemperatureController і TemperatureRamp.

class TemperatureController {

public:

TemperatureController(Location);

~TemperatureController();

void process(const TemperatureRamp&);

Minute schedule(const TemperatureRamp&) const;

private:

Heater h;

};

Клас TemperatureRamp тут використовується як частина сигнатури функції-члена process; це дає нам підстави сказати, що клас TemperatureController користується послугами класу TemperatureRamp.

Клієнти й сервери. Відношення використання між класами відповідає рівноправному зв'язку між їхніми екземплярами. Це те, у що перетворюється асоціація, якщо виявляється, що одна з її сторін (клієнт) користується послугами іншої (сервера). Приклад клієнт-серверних відношень показаний на рис. 15.9.

Насправді, один клас може використовувати інший по-різному. У нашому прикладі це відбувається в сигнатурі інтерфейсної функції. Можна задати, що TemperatureController всередині реалізації функції schedule використовує, наприклад, екземпляр класу Predictor (провісник). Відношення цілого й частини тут немає, оскільки цей об'єкт не входить в об'єкт TemperatureController, а тільки використовується. У типовому випадку таке відношення використання проявляє себе, якщо в реалізації якої-небудь операції відбувається оголошення локального об'єкта використовуваного класу.

Строге відношення використання іноді трохи обмежене, оскільки клієнт має доступ тільки до відкритої частини інтерфейсу сервера. Іноді з тактичних міркувань ми повинні порушити інкапсуляцію, для чого, властиво, і служать "дружні" відношення класів в C++.