- •Основи програмної інженерії Тема 1. Поняття програмної інженерії. Вступ
- •Процес створення програмного забезпечення
- •Моделі технологічного процесу створення пз
- •Моделі процесу розробки по
- •Характеристики якісного пз
- •Тема 2. Види моделей систем. Поняття і класифікація вимог до програмної системи.
- •Способи запису специфікацій вимог.
- •Види моделей систем.
- •Мова моделювання uml.
- •Об'єктні моделі
- •Інструментальні case-засоби.
- •Тема 3. Поняття архітектурного проектування. Архітектурні моделі.
- •Архітектурний шаблон mvc.
- •Особливості шаблону mvc.
- •Модель проблемної сфери.
- •Тема 4. Важливі функціональні засоби мови c#. Автоматично реалізовані властивості.
- •Ініціалізатори об'єктів та колекцій.
- •Автоматичне виведення типу.
- •Анонімні типи.
- •Використання методів розширення Методи розширення
- •Застосування методів розширення до інтерфейсу
- •Створення фільтруючих методів розширення
- •Тема 5. Лямбда-вирази. Мова linq. Лямбда-вирази.
- •Мова linq.
- •Методи розширення linq.
- •Відкладені запити linq.
- •Тема 6. Створення слабо зв'язаних компонентів. Впровадження залежності.
- •Контейнери впровадження залежності.
- •Бібліотека Ninject.
- •Порядок роботи з Ninject.
- •Тема 7. Засоби доступу до даних. Технологія ado.Net.
- •Реалізація доступу до даних.
- •Робота з даними.
- •Тема 8. Тестування пз. Розробка через тестування. Автоматизоване тестування пз та його види.
- •Розробка через тестування. Робочий потік "червоний-зелений-рефакторинг".
- •Модель "організація.Дія.Твердження".
- •Використання бібліотеки Moq
- •Тема 9. Проектування інтерфейсу користувача. Інтерфейс користувача.
- •Переваги графічного інтерфейсу.
- •Процес проектування графічного інтерфейсу.
- •Принципи проектування інтерфейсів користувача.
- •Шаблони.
- •Тема 10. Основи інженерії вимог. Розробка вимог.
- •Формування і аналіз вимог.
- •Опорні точки зору.
- •Сценарії.
- •Атестація вимог.
- •Тема 11. Прототипування програмних систем. Поняття прототипування.
- •Переваги прототипування.
- •Види прототипування.
- •Технології швидкого прототипування.
- •Тема 12. Покомпонентна розробка. Компоненти і класи об'єктів.
- •Компоненти як постачальники послуг.
- •Рівні абстракції компонентів.
- •Вимоги до компонентів.
- •Тема 13. Шаблони проектування. Структурні шаблони.
- •Поняття шаблону проектування.
- •Основні елементи шаблону.
- •Механізми повторного використання.
- •Структурні шаблони проектування.
Механізми повторного використання.
Успадкування та композиція
Два найбільш поширених прийоми повторного використання функціональності в об'єктно-орієнтованих системах – це спадкування класу і композиція об'єктів.
Повторне використання за рахунок породження підкласу називають ще прозорим ящиком (white-box reuse). Такий термін підкреслює, що внутрішній устрій батьківських класів видно підкласам .
Композиція об'єктів – це альтернатива успадкуванню класу. У цьому випадку нову, більш складну функціональність ми отримуємо шляхом об'єднання або композиції об'єктів. Для композиції потрібно, щоб поєднувані об'єкти мали чітко визначені інтерфейси. Такий спосіб повторного використання називають чорним ящиком (black-box reuse), оскільки деталі внутрішнього устрою об'єктів залишаються прихованими.
І у спадкування , і у композиції є достоїнства і недоліки. Успадкування класу визначається статично на етапі компіляції , його простіше використати, оскільки воно безпосередньо підтримується мовою програмування. У разі спадкування класів спрощується також завдання модифікації існуючої реалізації. Якщо підклас заміщує лише деякі операції, то це може стосуватися і інших успадкованих операцій, оскільки не виключено, що вони викликають заміщені.
Але у спадкування класу є й мінуси. По-перше, не можна змінити успадковану від батька реалізацію під час виконання програми, оскільки саме спадкування фіксоване на етапі компіляції. По-друге, батьківський клас нерідко хоча б частково визначає фізичне представлення своїх підкласів. Оскільки підкласу доступні деталі реалізації батьківського класу, то часто кажуть, що успадковання порушує інкапсуляцію. Реалізації підкласу та батьківського класу настільки тісно пов'язані, що будь-які зміни останньої вимагають зміни і реалізацію підкласу.
Залежність від реалізації може спричинити за собою проблеми при спробі повторного використання підкласу . Якщо хоча б один аспект успадкованої реалізації непридатний для нової предметної області, то доводиться переписувати батьківський клас або замінювати його чимось більш підходящим. Така залежність обмежує гнучкість і можливості повторного використання. З проблемою можна впоратися, якщо наслідувати тільки абстрактним класам, оскільки в них зазвичай зовсім немає реалізації або вона мінімальна.
Композиція об'єктів визначається динамічно під час виконання за рахунок того, що об'єкти отримують посилання на інші об'єкти. Композицію можна застосувати, якщо об'єкти підтримують однакові інтерфейси. Для цього, у свою чергу, потрібно ретельно проектувати інтерфейси таким чином, щоб один об'єкт можна було використовувати разом з широким спектром інших. Але й виграш великий. Оскільки доступ до об'єктів здійснюється тільки через їх інтерфейси, ми не порушуємо інкапсуляцію. Під час виконання програми будь-який об'єкт можна замінити іншим, лише б він мав той же тип. Більше того, оскільки при реалізації об'єкта кодуються насамперед його інтерфейси, то залежність від реалізації різко знижується.
Композиція об'єктів впливає на дизайн системи і ще в одному аспекті . Надання переваги композиції об'єктів, а не успадкуванню класів, дозволяє інкапсулювати кожен клас і дати йому можливість виконувати тільки своє завдання. Класи і їх ієрархії залишаються невеликими, і ймовірність їх розростання до некерованих розмірів мала. З іншого боку, дизайн, що базується на композиції, міститиме більше об'єктів (хоча число класів, можливо, зменшиться), і поведінка системи почне залежати від їх взаємодії, тоді як при іншому підході вона була б визначена в одному класі.
Звідси випливає друге правило об'єктно- орієнтованого проектування: віддавайте перевагу композиції а не успадкуванню класу.
В ідеалі, щоб домогтися повторного використання, взагалі не варто було б створювати нові компоненти. Добре було б мати можливість отримання усієї потрібної функціональності простим збиранням в єдине ціле вже існуючих компонентів. На практиці, однак, так виходить рідко, оскільки набір наявних компонентів все ж недостатньо широкий. Повторне використання за рахунок успадкування спрощує створення нових компонентів, які можна було б застосовувати зі старими. Тому успадкування і композиція часто використовуються разом.
Делегування
За допомогою делегування композицію можна зробити таким же потужним інструментом повторного використання, як і успадкування. При делегуванні в процес обробки запиту залучено два об'єкти: одержувач доручає виконання операцій іншому об'єкту – уповноваженому. Приблизно так само підклас делегує відповідальність свого батьківського класу. Але успадкована операція завжди може звернутися до об'єкта-одержувача через змінну-член (в С++) або змінну self (у Smalltalk). Щоб досягти того ж ефекту для делегування, одержувач передає покажчик на самого себе відповідному об'єкту, щоб при виконанні делегованої операції останній міг звернутися до безпосереднього адресата запиту.
Наприклад , замість того щоб робити клас Window (вікно ) подклассом класу Rectangle (прямокутник) – адже вікно є прямокутником, – ми можемо скористатися всередині Window поведінкою класу Rectangle, помістивши в клас Window змінну примірника типу Rectangle і делегуючи їй операції, специфічні для прямокутників. Іншими словами , вікно не є прямокутником, а містить його. Тепер клас Window може явно перенаправляти запити своєму члену Rectangle, а не наслідувати його операції.
На діаграмі нижче зображений клас Window, який делегує операцію Area() над своєю внутрішньою областю змінній примірника Rectangle.
Суцільна лінія зі стрілкою позначає, що клас містить посилання на екземпляр іншого класу. Це посилання може мати необов'язкове ім'я, в даному випадку прямокутник.
Головне достоїнство делегування в тому, що воно спрощує композицію поводжень під час виконання. При цьому спосіб комбінування поводжень можна змінювати. Внутрішню область вікна дозволяється зробити круглою під час виконання, просто підставивши замість екземпляра класу Rectangle екземпляр класу Circle (передбачається, що обидва класи мають однаковий тип).
У делегування є й недолік, який властивий і іншим підходам, що застосовуються для підвищення гнучкості за рахунок композиції об'єктів. Полягає він у тому, що динамічну, у високому ступені параметризовану програму важче зрозуміти, ніж статичну. Є, звичайно, і деяка втрата машинної продуктивності, але неефективність роботи проектувальника набагато більш істотна. Делегування можна вважати хорошим вибором лише тоді, коли воно дозволяє досягти спрощення, а не ускладнення дизайну. Нелегко сформулювати правила, які ясно говорять, коли слід користуватися делегуванням, оскільки ефективність його залежить від контексту і особистого досвіду проектувальника. Найкраще делегування працює при використанні у складі звичних ідіомах, тобто в стандартних патернах.
Делегування використовується в декількох патернах проектування: стан, стратегія, відвідувач. У першому одержувач делегує запит об'єкту, який представляє його поточний стан. У паттерні стратегія обробка запиту делегується об'єкту, який представляє стратегію його виконання. У об'єкта може бути тільки один стан, але багато стратегій для виконання різних запитів. Призначення обох патернів – змінити поведінку об'єкта за рахунок заміни об'єктів, яким делегуються запити. У патерні відвідувач операція, яка повинна бути виконана над кожним елементом складеного об'єкта, завжди делегується відвідувачеві.
В інших патернах делегування використовується не так інтенсивно. Патерн посередник вводить об'єкт, який здійснює посередництво при взаємодії інших об'єктів. Іноді об'єкт-посередник реалізує операції, переадресуючи їх іншим об'єктам; в інших випадках він передає посилання на самого себе, використовуючи тим самим делегування як таке. Патерн ланцюжок обов'язків обробляє запити, перенаправляючи їх від одного об'єкта іншому по ланцюжку. Іноді разом із запитом передається посилання на вихідний об'єкт, що отримав запит, і в цьому випадку ми знову стикаємося з делегуванням. Патерн міст відокремлює абстракцію від її реалізації. Якщо між абстракцією і конкретною реалізацією є істотна схожість, то абстракція може просто делегувати операції своїй реалізації.
Делегування показує, що успадкування як механізм повторного використання завжди можна замінити композицією.
Успадкування та параметризрвані типи
Ще один (хоча і не в точності об'єктно-орієнтований) метод повторного використання наявної функціональності – це застосування параметризованих типів, відомих також як узагальнені типи (Ada, Eiffel) або шаблони (С++). Дана техніка дозволяє визначити тип, не вказуючи типи, які він використовує. Неспецифіковані типи передаються у вигляді параметрів в точці використання. Наприклад, клас List (список) можна параметризовані типом елементів, які додаються у список. Для кожного типу елементів компілятор мови створить окремий варіант шаблону класу List.
Параметризовані типи – це третій (після успадкування класу і композиції об'єктів) спосіб комбінувати поведінку в об'єктно-орієнтованих системах.
Багато задач можна вирішити за допомогою будь-якого з цих трьох методів. Щоб параметризувати процедуру сортування операцією порівняння елементів, можна зробити порівняння:
операцією , реалізованою підкласами (застосування патерну шаблонний метод);
функцією об'єкта , переданого процедурі сортування ( стратегія);
аргументом шаблону в С++ або узагальненого типу в Ada, який задає ім'я функції, що використовується для порівняння елементів.
Але між трьома даними підходами є важливі відмінності.
Композиція об'єктів дозволяє змінювати поведінку під час виконання, але для цього потрібні непрямі виклики, що знижує ефективність. Успадкування дозволяє надати реалізацію за замовчуванням, яку можна заміщувати у підкласах. За допомогою параметрезованих типів допустимо змінювати типи, що використовуються класом. Але ні успадкування, ні параметризрвані типи не підлягають модифікації під час виконання. Вибір того чи іншого підходу залежить від проекту і обмежень на реалізацію.
