|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Тема 2. Принципи проектування програмного забезпечення на основі аналізу предметної області
Паттерни описують рушійні сили, мотиви і відносини для визначеної проблеми у визначеному контексті і пропонують найкращій, перевірений підхід до її рішення. Цінність приховання реалізації полягає в тому, що завдяки йому паттерни дозволяють легко додавати нові реалізації, тому що об’єкти-клієнти нічого не знають про те, як працюють вже існуючі реалізації. У практиці проектування для роботи з елементами, що змінюються, застосовуються дві основні стратегії [6]. - знайти те, що змінюється, і інкапсулювати це; - надавати перевагу композиції замість спадкуванню. Раніше для координації елементів, що змінюються, розробники часто створювали великі схеми спадкування класів. Однак друга з приведених вище стратегій рекомендує скрізь, де тільки можливо, заміняти спадкування композицією. Ідея полягає в тому, щоб інкапсулювати зміни в незалежних класах, що дозволить при обробці майбутніх змін обійтися без модифікації програмного коду. Одним зі способів досягнення подібної мети є розташування кожного підданого змінам елемента у власний абстрактний клас з наступним аналізом, як ці абстрактні класи співвідносяться один з одним. Звернемося до рис. 1.1, на якому відображено взаємозв’язки між наступними концепціями: - аналіз спільності й аналіз змінності; - концептуальний рівень, рівні специфікації та реалізації; - абстрактний клас, його інтерфейс і похідні від нього класи. Як показано на рис. 1.1, аналіз спільності має відношення до концептуального рівня проекту системи, тоді як аналіз змінності відноситься до рівня його реалізації, тобто до процедур конкретного втілення системи. Рівень специфікацій займає проміжне положення між двома іншими рівнями розробки системи. Тому він передбачає виконання обох видів аналізу. На рівні специфікацій визначається, як буде відбуватися взаємодія з безліччю об’єктів, що концептуально схожі один з одним - тобто кожний з цих об’єктів представляє конкретний варіант деякої загальної концепції. На рівні реалізації кожна така загальна концепція описується абстрактним класом або інтерфейсом. Взаємозв’язок між рівнем специфікацій і концептуальним рівнем можна описати так. На рівні специфікацій визначається інтерфейс, що необхідний для реалізації усіх варіантів прояву (варіацій) деякої концепції (спільності), виявленої на концептуальному рівні. Подібний підхід спрощує процес проектування класів і зводить його до процедури з двох етапів, описаних у табл. 2.1.
Таблиця 2.1 – Проектування класів
Аналіз спільності/змінності дозволяє знайти концептуальне рішення (спільність) і підготувати рішення на рівні реалізації (кожна конкретна варіація). Якщо враховувати тільки спільності й об’єкти, що використовують їх, то можна підійти до рішення проблеми з іншого боку – за допомогою методу декомпозиції на зобов’язання. Отже, не варто обмежувати себе тільки об’єктно-орієнтованою декомпозицією (тобто розкладанням проблемної області на об’єкти), буде корисно також спробувати розкласти проблемну область на зобов’язання, що може виявитися навіть простіше. У цьому випадку можливо попередньо визначити об’єкти, що потребуються для реалізації знайдених зобов’язань, і лише потім переходити до звичайної об’єктної декомпозиції. Це правило можна розуміти як вимога декомпозиції поставленої задачі на дві частини: - визначити, які об’єкти необхідні; - прийняти рішення, як будуть створюватися екземпляри цих об’єктів. Ті або інші паттерни часто підказують, як можна виконати декомпозицію зобов’язань. Наприклад, паттерн Decorator демонструє, як забезпечити гнучке комбінування об’єктів, якщо після декомпозиції ПрО включає набір основних зобов’язань, що використовуються завжди (клас ConcreteComponent), і деяка безліч варіацій, використовуваних від випадку до випадку (класи-декоратори). Паттерн Strategy демонструє декомпозицію проблеми на об’єкти, що використовують правила, та використовувані правила. Практичний досвід розробки ПЗ говорить, що будь-який отриманий результат завжди підлягає ретельній перевірці. Одним з індикаторів поганого дизайну системи можуть бути наступні негативні явища в програмному коді(code smell) [7]: - дубляж коду: однаковий або майже однаковий код, у різних місцях проекту; - великі методи: підпрограми з великою кількістю ліній коду; - великі класи: на один клас покладено занадто багато, найчастіше, різнорідних функцій; - заздрість: клас надмірно використовує методи іншого класу; - порушення приватності: клас надмірно залежить від деталей реалізації іншого класу; - порушення заповіту: клас перевизначає метод базового класу й при цьому порушує його контракт (тобто первісне призначення); - ледачий клас: клас, що робить занадто мало, тобто клас із недостатньою або нецілісною функціональністю; - надмірна складність: примусове використання складних рішень, де простий дизайн був би достатнім; - надмірно довгі ідентифікатори: у тому числі, використання довгих імен, для позначення залежностей, які повинні бути неявними. Системи необхідно проектувати з урахуванням їх подальшого розвитку. Для проектування системи, стійкої до таких змін, варто продумати, як вона буде змінюватися протягом відведеного їй часу життя. Якщо при проектуванні системи не приймалася до уваги можливість змін, тобто ймовірність, що в майбутньому її прийдеться повністю перепроектувати – це може викликати перевизначення й нову реалізацію класів, модифікацію і повторний цикл тестування. Типові причини перепроектування [8]: - при створенні об’єкта явно вказується клас. Оголошення імені класу прив’язує до конкретної реалізації, а не до конкретного інтерфейсу. Це може ускладнити зміну об’єкта в майбутньому. Щоб уникнути такої проблеми, необхідно створювати об’єкти побічно. Для розв’язання проблеми можуть допомогти паттерни проектування: Абстрактна фабрика, Фабричний метод, Прототип; - залежність від конкретних операцій. Задаючи конкретну операцію, ви обмежуєте себе єдиним способом виконання запиту. Якщо ж не включати запити в код, то буде простіше змінити спосіб виконання запиту як на етапі компіляції, так і на етапі виконання. Для розв’язання проблеми можуть допомогти паттерни проектування: Ланцюжок зобов’язань, Команда; - залежність від апаратної й програмної платформ. Зовнішні інтерфейси операційної системи й інтерфейси прикладних програм (APІ) різні на різних програмних й апаратних платформах. Якщо програма залежить від конкретної платформи, її буде трудніше перенести на інші. Навіть на «рідній» платформі таку програму важко підтримувати. Тому при проектуванні систем так важливо обмежувати платформні залежності. Для розв’язання проблеми можуть допомогти паттерни проектування: Абстрактна фабрика, Міст; - залежність від алгоритмів. Під час розробки й наступного використання алгоритми часто розширюються, оптимізуються й заміняються. Залежні від алгоритмів об’єкти прийдеться переписувати при кожній зміні алгоритму. Тому алгоритми, імовірність зміни яких висока, варто ізолювати. Для розв’язання проблеми можуть допомогти паттерни проектування: Міст, Ітератор, Стратегія, Шаблонний метод, Відвідувач; - сильна зв’язаність. Сильно зв’язані між собою класи важко використати порізно, тому що вони залежать один від одного. Сильна зв’язаність приводить до появи монолітних систем, у яких не можна не змінити, не видалити клас без знання деталей і модифікації інших класів. Таку систему важко вивчати, переносити на інші платформи й супроводжувати. Слабка зв’язаність підвищує ймовірність того, що клас можна буде повторно використати сам по собі. При цьому вивчення, переніс, модифікація й супровід системи набагато спрощуються. Для підтримки слабо зв’язаних систем у паттернах проектування застосовуються такі методи, як абстрактні зв’язки й розбивка на шари. Можуть допомогти паттерни проектування: Абстрактна фабрика, Міст, Ланцюжок обов’язків, Команда, Фасад, Посередник, Спостерігач; - розширення функціональності за рахунок породження підкласів. Спеціалізація об’єкта шляхом створення підкласу часто виявляється непростою справою. З кожним новим підкласом зв’язані фіксовані витрати реалізації (ініціалізація, очищення й т.д.). Для визначення підкласу необхідно також ясно представляти собі структуру батьківського класу. Наприклад, для заміщення однієї операції може знадобитися замістити й інші. Заміщення операції може виявитися необхідним для того, щоб можна було викликати успадковану операцію. Крім того, породження підкласів веде до комбінаторного росту числа класів, оскільки навіть для реалізації простого розширення може знадобитися багато нових підкласів. Для представлення паттернів у вигляді архітектурних рішень найчастіше використовуються діаграми класів UML, де клас задається у вигляді прямокутника, яких розділено на 3 частини: назва (для абстрактних класів – назва записується курсивом), список властивостей та список методів [9]. Фактично існує два різних види відносин has a. Один об’єкт може містити інший об’єкт, що або є його частиною, або ні. На рис. 2.1 показано клас Aіrport (аеропорт), що містить клас Aіrcraft (літальний апарат). Клас Aіrcraft не є частиною класу Aіrport, але можна сказати, що клас Aіrport містить його. Цей тип відносин одержав назву агрегації.
Рис. 2.1. Схема агрегації класів
На діаграмі (рис. 2.1) також показано, що від класу Aіrcraft породжені класи Jet (реактивний літак) і Helіcopter (вертоліт). Можна зробити висновок, що клас Aіrcraft є абстрактним класом, оскільки його ім’я виділене курсивом. А це значить, що клас Aіrport буде включати або об’єкт класу Jet, або об’єкт класу Helіcopter, але звертатися до цих об’єктів він буде однаково – як до об’єкту класу Aіrcraft. Порожній (незафарбований) ромб із правої сторони класу Aіrport указує на відношення агрегації між ним і класом Aіrcraft. Другий тип відносин has a полягає в тому, що вкладений об’єкт є частиною того об’єкта, в якому він утримується. Такий тип відносин одержав назву узагальнення. На рис. 2.2 показано, що клас Tіre (шини) є частиною класу Car (машина) – тобто машина складається із шин і, імовірно, інших деталей. Подібний тип відносин has a, називаний об’єднанням, представляється зафарбованим ромбом. На цій діаграмі (рис. 2.2) також показано, що клас Car використовує клас GasStatіon (автозаправна станція). Відношення використання представлене пунктирною лінією зі стрілкою. Інакше його іноді називають відношенням взаємозв’язку.
Рис. 2.2. Схема композиції об’єктів
Як об’єднання, так і агрегація припускають, що об’єкт містить один або більше інших об’єктів. Але об’єднання має на увазі, що один об’єкт є частиною іншого об’єкта, тоді як агрегація означає, що вкладені об’єкти є скоріше деякими наборами або колекціями самостійних елементів. Об’єднання можна розглядати як нероздільний взаємозв’язок, коли час існування вкладених об’єктів визначається об’єктом, який їх містить. У даному випадку функції створення і видалення вкладених об’єктів доцільно покласти на методи конструктора і деструктора, об’єкта, що їх включає. Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.005 сек.) |