1. Бублик Володимир Васильович Програмування - 2 Лекція 4 . Об'єктне програмування. Ієрархія об’єктів: композиція і агрегація Лекції для студентів 2 курсу
2. Типи ієрархії об'єктів // Layering : вкладання class AnyClass { T _composee; T& _refferee; T* _agregee; };
4. Приклад 1. Відрізок // Composite class Segment { private : // Components Point _a, _b; ……………… };
5. Приклад 2. Трикутник // Композиція вершин class Triangle { private : Point _a, _b, _c; ........................ };
6. Приклад 3. Знову трикутник // Композиція сторін class Triangle { private : Segment _a b , _b c , _c a ; …………………………… . }; Композити самі можуть бути компонентами інших об'єктів: Композит Triangle містить компонентами три композити Segment
7. Приклад 4. Все той же трикутник // Композиція вершин і сторін class Triangle { private : Point _a, _b, _c; Segment _ab, _bc, _ca; ........................ };
8. Тривалість життя: створення компонент Компоненти створюються конструктором композиту: звичайним або копіювальним Triangle::Triangle ( const Point& a, const Point& b, const Point &c): // Ініціалізація компонент _a(a), _b(b), _c(c) { return; }
9. Тривалість життя: видалення компонент Компоненти не вимагають окремого видалення, оскільки вони видаляються автоматично власними деструкторами при видаленні композиту як його атрибути ~ Triangle ::Triangle() { // _a.~Point(); // _b.~Point(); // _c.~Point(); return ; }
10. Права доступу Звичайно доступ до компонент та їх методів зовні композиту закрито (компоненти служать атрибутами композиту, а атрибути, як правило, закриті) Композит сам не має доступу до закритої частини компоненту Композит має доступ до відритої частини компоненту, при необхідності він може делегувати цей доступ нагору
11. Доступ до атрибутів: селектор Оскільки компоненти закриті, доступ (модифікація) забезпечуються селекторами (модифікаторами) class Triangle { private : Point _a, _b, _c; public : const Point& apexA() const ; const Point& apexB() const ; const Point& apexC() const ; };
12. Реалізація селектора const Point& Triangle::apexA() const { return _a; } Чим відрізняються одна від одної ці реалізації? const Point Triangle::apexA() const { return _a; }
13. Делегування // Delegation of methods class Triangle { private : Segment _a b , _b c , _c a ; public : // delegators double length_ab () const ; double length_bc () const ; double length_ca () const ; };
14. Реалізація делегатів // Delegator // трикутник делегує довжину відрізку double Triangle::length_ab() const { // Delegate // метод трикутника звертається // до методу сегмента, недоступного зовні return _ab.length(); }
15. Неделеговані методи Реалізація методів композиту може використовувати відкриту частину компоненти або асоційованого об'єкту як будівельний матеріал double Triangle::square() const { // length() і distance(_a) методи відрізка return 0.5*side_a().length()*side_a().distance(_a); } Звідки візьмуться відрізки у варіанті трикутника, складеного лише з вершин?
16. Асоційовані об'єкти Об'єкти не завжди вкладаються один в інший Асоційовані об'єкти ( associate ) можуть будуватися на замовлення і існувати поза асоціатором ( associator )
17. Асоційовані об'єкти // Associator class Triangle { private: Point _a, _b, _c; public : // Associate : сторона трикутника const Segment side_a() const ; };
23. Варіант надлишкової композиції class Triangle { private : Point _a, _b, _c; // Асоціанти стали компонентами Segment _ab, _bc, _ca; public : const Point& apexA() const ; // Делегати стали селекторами const Segment & side_a() c onst ; } ;
24. Селектор замість делегата // Селектор сторони трикутника const Segment& Triangle::side_a() const { return _bc; // return Segment(_b, _c); }
25. Конструювання компонентів Triangle::Triangle ( const Point& a, const Point& b, const Point &c): // Багато зайвих копій _a(a), _b(b), _c(c), _ab(Segment(a, b)), _bc(Segment(b, c)), _ca(Segment(c, a)) { return ; }
26. Consistency ( сумісність ) Надлишкове копіювання шкідливе можливою несумісністю Візьмемо трикутник t, з вершинами a, b і c; сторонами _bc, _ca і _ab . Змінимо значення вершини a , але забудемо змінити значення сторін _ca і _ab. Трикутник t виявиться несумісним. Проблема сумісності не виникає, якщо трикутник задано лише вершинами
27. Як правильно обрати компоненти композиту? // Трикутник за трьома сторонами class Triangle { private : Segment _ab, _bc, _ca; public : // а конструктор, як раніше за трьома вершинами Triangle(const Point &, const Point&, const Point&); } ;
28. Конструювання сторін Triangle::Triangle ( const Point& a, const Point& b, const Point &c): _ab(Segment(a, b)), _bc(Segment(b, c)), _ca(Segment(c, a)) { return ; }
30. Знову по сумісність Трикутник складений із сторін знову може стати несумісним при спробі змінити одну із сторін, не змінивши іншої, прилеглої сторони. Проблема: надлишкове кодування приводить до несумісності Рішення: використовувати розвиненіші форми вкладень, а саме агрегацію.
34. Агрегація Кожен нетривіальний об'єкт є агрегатом, складеним зі своїх атрибутів Атрибути можуть бути об'єктами ― композиція; указниками ― агрегація указниками; відсилками ― агрегація відсилками
35. Агрегація указниками Агрегація указниками відрізняється від композиції тривалістю життя: деструктор агрегату сам відповідає за видалення агрегованого об'єкту class Agregate { private : Agregee * _agregee ; public : Agregate(): _agregee(0){}; ~Agregate() { delete _agregee ; } };
36. Сторони, агреговані в трикутник class Triangle { private : Point _a, _b, _c; Segment *_ab, *_bc, *_ca; public : Triangle( const Point &, const Point&, const Point& c); ~Triangle(); }
37. Конструктор агрегату Triangle::Triangle ( const Point& a, const Point& b, const Point &c): _a(a), _b(b), _c(c), // Сторони обчислюються і агрегуються // на замовлення (on demand) _ab(0), _bc(0), _ca(0) { return ; }
38. Деструктор агрегату Triangle::~Triangle() { if (_ab!=0) delete _ab; // vs delete _ab; if (_bc!=0) delete _bc; if (_ca!=0) delete _ca; }; Питання: чи необхідна перевірка на нуль?
39. Модифікований селектор // Сторона трикутника const Segment& Triangle::side_a() const { // Якщо не обчислювали раніше if (_bc == 0) // Обчислюємо і запам'ятовуємо _bc = new Segment(_b, _c); return *_bc; }
41. Агрегація відсилкою Використовується для агрегування об'єктів, тривалість життя яких перевищує тривалість життя агрегату. За створення і видалення агрегованих відсилкою об'єктів агрегат відповідальності не несе class Agregate { private : Agregee & _agregee ; public : Agregate ( const Agregee & original): _agregee (original) {}; };
42. Вершини, агреговані в сторону class Segment { private : // Агреговані вершини Point & _a, & _b; ……………… }; Що гарантує сумісність?
43. Збалансований трикутник // Кінці відрізків // відсилають // до вершин // трикутника class Segment { private : Point & _a, & _b; }; //Сторони трикутника // агреговані указниками class Triangle { private: Point _a, _b, _c; Segment * _ab, * _bc, * _ca; };
49. Висновок Головна проблема у створенні агрегатів полягає у виборі правильного типу вкладень залежно від тривалості життя об'єктів з метою досягнення максимальної сумісності