ПЕРЕЛІК ДИСЦИПЛІН:
  • Адміністративне право
  • Арбітражний процес
  • Архітектура
  • Астрологія
  • Астрономія
  • Банківська справа
  • Безпека життєдіяльності
  • Біографії
  • Біологія
  • Біологія і хімія
  • Ботаніка та сільське гос-во
  • Бухгалтерський облік і аудит
  • Валютні відносини
  • Ветеринарія
  • Військова кафедра
  • Географія
  • Геодезія
  • Геологія
  • Етика
  • Держава і право
  • Цивільне право і процес
  • Діловодство
  • Гроші та кредит
  • Природничі науки
  • Журналістика
  • Екологія
  • Видавнича справа та поліграфія
  • Інвестиції
  • Іноземна мова
  • Інформатика
  • Інформатика, програмування
  • Юрист по наследству
  • Історичні особистості
  • Історія
  • Історія техніки
  • Кибернетика
  • Комунікації і зв'язок
  • Комп'ютерні науки
  • Косметологія
  • Короткий зміст творів
  • Криміналістика
  • Кримінологія
  • Криптология
  • Кулінарія
  • Культура і мистецтво
  • Культурологія
  • Російська література
  • Література і російська мова
  • Логіка
  • Логістика
  • Маркетинг
  • Математика
  • Медицина, здоров'я
  • Медичні науки
  • Міжнародне публічне право
  • Міжнародне приватне право
  • Міжнародні відносини
  • Менеджмент
  • Металургія
  • Москвоведение
  • Мовознавство
  • Музика
  • Муніципальне право
  • Податки, оподаткування
  •  
    Бесплатные рефераты
     

     

     

     

     

     

         
     
    Агрегація або спадкування ?
         

     

    Інформатика, програмування

    Агрегація або успадкування?

    Євген Каратаєв

    І знову про проектування класів. Хвора тема і місце застосування безлічі трюків. Більшість програмістів використовують трюки по-різному. способу їх застосування - 1) несвідомо, 2) усвідомлено, але з труднощами при виборі способу і 3) усвідомлено і, більше того, трюки обчислюються.

    Розглянемо питання вибору шляху під час розв'язання задачі типу "додати нову функціональності ". Є модуль у вигляді набору класів, який за функціональності частково підходить до того, що треба отримати. Є завдання додати модуль якусь функціональність. Є небажання багато працювати і мати в подальшому з отриманим кодом проблеми. При бажанні в ці умови завдання можна, думаю, вписати практично будь-яку программерскую завдання.

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

    При агрегації ми не отримаємо нового класу і для обох завдань, старою і новою, використовуємо один і той самий клас. Агрегацію ми можемо отримати не тільки як спосіб вирішити нове завдання, але і як спосіб виправити помилки в старій завдання, оскільки виправлення коду автоматично впливають на стару задачу. При агрегації до класу додається одне або два поля, завдяки яким і відбувається розрізнення старої та нової функціональності. А саме за значенням цих полів. Наприклад, доданий поле має сенс номера версії, в залежності від значення якої в модифікованому класі розрізняється поведінку декількох функцій. Цим способом ми можемо уникнути рутини з великою кількістю модифікацій завдання. Що є типовим ознакою сучасного проекту. Додаємо полі, і при змінах у специфікації коректуємо поведінку декількох функцій. Перевизначати віртуальні функції зі зрозумілих причин немає необхідності.

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

    Зведемо порівняльні відмінності в таблицю.        

    Вид відмінності         

    Агрегація         

    Спадкування             

    1. Додавання нових полів         

    Швидше за все, оскільки слід   розрізняти стану об'єкта як старого класу і як нового класу         

    Необов'язково, оскільки   функціональність може бути реалізована швидше за все шляхом перевизначення   віртуальних функцій.             

    2. Перевизначення віртуальних   функцій         

    Немає сенсу         

    Швидше за все             

    3. Збереження працездатності   наявного коду         

    Сумнівно. Наявний код   буде заводити об'єкти вже модифікованого класу, а модифікація   проводилася з метою іншого завдання         

    Безумовно. Зміни не   стосуються наявного коду.             

    4. Досяжність поставленої   мети         

    Так, швидше за все.         

    Так, швидше за все.             

    5. Наявність особливих вимог до   наявному класу         

    Ні. Якщо чогось у ньому не   вистачає, то це буде дописано.         

    Так. Базовий клас повинен   передбачити можливість спадкування (наприклад, оголосити віртуальний   деструктор) і надати частину своїх функцій як віртуальні.             

    6. Наявність особливої уваги до   наявному коду класу, контрольні точки         

    Так. Етапи ініціалізації та   деініціалізацію об'єктів повинні бути проконтрольовані обов'язково.   Бажано з метою збереження сумісності з попереднім поведінкою об'єкта.         

    Ні, якщо кошти реалізації   підтримують автоматичний виклик конструкторів і віртуальних деструкторів та   так, якщо не підтримують.             

    7. Наявність особливих вимог до   попереднього оперативного оточенню на етапі створення/видалення об'єкта         

    Ніяких. Для оточення нічого   не змінюється.         

    Так. Точки створення об'єктів   повинні бути перевірені на предмет створення об'єктів саме потрібного класу.             

    8. Наявність особливих вимог до   попереднього оперативного оточенню на етапі життя об'єкта         

    Можливо, якщо модифікований   код змінює своє ставлення до зовнішнього контексту.         

    Ніяких. Попереднє оперативне   оточення бачить і повинна бачити базовий клас. Якщо перевизначають   віртуальні функції змінюють відношення об'єкта до контексту, можуть бути   проблеми.             

    9. Розростання коду наявної   програми         

    Так, безумовно.         

    Ні.     

    Ці пункти слід враховувати, якщо проектування класів проводиться не спонтанно і "по живому", а більш-менш відповідально. Тим більше, що завжди є час обміркувати свої кроки.

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

    Розглянемо вікна в Windows. Вікна в Windows все і незалежно ні від чого мають дві основні характеристики - це визначення класу і функція обробки повідомлень. Це пункт номер раз, який відомий всім. Крім того, вікна в Windows мають чітку градацію на 4 види, що розрізняються як деталями функції обробки повідомлень, так і ставленням до нього системи управління вікнами. Ця різниця визначається функціями за замовчуванням, які викликає програміст, якщо не обробляє будь-які листи. Це функції DefWindowProc, DefDialogProc, DefMDIChildProc і DefMDIFrameProc.

    Класика об'єктно-орієнтованого проектування підказує, що слід, як мінімум, у графі наслідувань передбачити клас, який реалізує абстрактне вікно. З тим, щоб згодом цей клас можна було використовувати для написання як цих 4 видів вікон, так і довільних контролів. Відносно уточнення поведінки вікна конкретного виду граф наслідувань класу вікна в даному випадку особливої ролі не грає. Постає питання - що вибрати для реалізації цих чотирьох видів вікон - агрегацію або успадкування з отриманням ще чотирьох або більше класів?

    Реалізація як бібліотек OWL, так і MFC вибрала шлях успадкування. Отримані додаткові класи, що реалізують відповідно просто несе вікно, контрол приватного виду, діалогове вікно, MDI Frame і MDI Child (як сказав Пушкін, "... прости, не знаю як перекласти. "). В результаті для використання кожного з цих класів потрібно крім загального коду, що оперує базовим класом вікна, приватний код, який може бути викликаний тільки для конкретних класів. Там, де використовується специфіка MDI Child, може бути використаний код тільки для нього. Більше того - код виклику, специфічний для MDI Child, може користуватися тільки цим класом або його спадкоємцем.

    Програміст, використовує бібліотеку класів, зобов'язується при написанні програми створювати спадкоємця відповідного класу. Таким чином, специфіка вікон у такому підході проектування вилилася не тільки в код спеціальних класів, а й у існування коду, що застосовується тільки до даного класу та існуючим поза його. Цей факт знайшов відображення в тому, що вбудовані в середовища розробки Borland C + + і Visual C + + майстра класів при спробі створення нових класів, що несуть прикладну навантаження, обов'язково вимагають вказівки базового класу і наступну модифікацію виробляють з урахуванням цих декількох базових класів. Уніфікований візуальний дизайнер вікон у такому підході є або майже нереалізовані завдання, або є об'єднанням 4-х дизайнерів. В обох цих середовищах більш-менш повноцінно реалізовано візуальне редагування лише для діалогових вікон.

    Реалізація бібліотеки VCL пішла шляхом агрегування можливостей і написання базового класу (TForm) таким чином, що різниця між 4-ма видами вікон зводиться до вказівки значення поля даних. При цьому код класу містить код для всіх 4-х видів вікон. Стає неможлива побудова програми, що використовує тільки діалогові вікна і не містить коду підтримки MDI. При цьому стає можливим використання єдиного візуального дизайнера для редагування всіх 4-х видів вікон. Наявність ж функцій підтримки MDI в об'єкта, що використовується як діалогового вікна мало кого бентежить, оскільки ці функції для діалогових вікон просто не приходить в голову викликати. Більше того - у програміста є впевненість, що те, що він проектує як звичайний спливаючі вікна в інтерфейсі SDI, завжди можна буде використовувати так само як і MDI Frame, і MDI Child, і простого модального діалогу. Більше того, зберігається можливість міняти показ цього вікна залежно від стану програми. Наприклад, у деяких випадках MDI Child повинен бути показаний в модальному режимі.

    Плюси і мінуси вибору графа успадкування видно вже на конкретному наведеному прикладі. В інших випадках слід визначатися з вибором, виходячи з конкретного завдання. Що цікаво, на вибір може вплинути знання не тільки наявною завдання і її цілей, але й наступних перспектив роботи. Як показала практика застосування вищезазначених засобів розробки, тобто Borland C + +/Visual C + + та Delphi / Borland C + + Builder, на перших двох успішно будувалися довго що розробляються проекти, складні за своєю організацією і слабко залежать від різноманітності інтерфейсу (або вийшли такими). Другі два кошти використовувалися для дійсно швидкої і якісної розробки проектів, що мають розвинені інтерфейсні засоби. Сама можливість застосування єдиного візуального дизайнера вікон стала свого роду каталізатором виникнення спільноти компонентного підходу.

    Слід відзначити, що компонентний підхід, який застосовується в Visual C + + (ActiveX), зарекомендував себе як більш інертного. Спадкування дельфійських компонентів і перевизначення їх віртуальних функцій виконати набагато простіше, ніж успадкування і перевизначення віртуальних функцій ActiveX контролів. Друге виконати просто неможливо, оскільки слід успадковувати не клас з частково реалізованим поведінкою, а інтерфейси, взагалі не містять реалізації. Якщо емулювати поведінка схожого класу ще можливо, то злегка перевизначити його віртуальні функції - вже велика спортивна проблема. Залишається хіба що повністю інкапсулювати вихідний клас як властивості і повністю перевизначати реалізовані їм інтерфейси делегуючи їх реалізацію інкапсульованими цього об'єкту.

    Які висновки/рекомендації можна зробити для себе? Якщо потрібно зробити кілька об'єктів, які розрізняються несуттєво і мають масу спільного, то гарним вибором може бути використання агрегування властивостей і зміни необхідних функцій з урахуванням їх стану. Якщо архітектура програми за своєю будовою використовує масу об'єктів, які видно цій архітектурі зовсім безвідносно властивостей, якими вони відрізняються, і методи, якими ці об'єкти розрізняються, істотні, то швидше за все слід вибрати шлях успадкування.

    Як можна визначити, що віднести в додаються властивостям при агрегування, а що до додаються/перевизначають при спадкуванні?

    Візьмемо і намалюємо квадратики/кружки, які відповідають різним поняттям. У них виділимо властивості та методи. Після чого згрупуємо ті квадратики, які мають загальні властивості та методи. Це перетин властивостей/методів слід виділити в новий квадратик і назвати його базовим, а ті квадратики, які об'єднувалися, назвати спадкоємцями цього базового. І залишити як доповнення до успадкованих те, що не потрапило в перетин. Тепер стоїть питання - який шлях вибрати? Якщо залишити все як є, то вийде варіант проектування нових класів шляхом успадкування. Якщо цікавить питання одержання нових класів шляхом агрегування, то квадратики слід об'єднати в один або більше. У отриманий укрупнений квадратик кожен, хто входить у нього внесе щось своє.

    Слід подивитися, чи можна частину властивостей що знаходяться в об'єднанні, але не перебувають в перетині, об'єднати в одну або більше. Чи є вони взаємовиключними? Чи можуть вони представляти стан об'єкта одержуваного класу? Якщо так, то ймовірність успішної агрегації вельми висока. Наявність в вихідному класі властивостей і методів, можливість використання яких може залежати не від класу об'єкта, а від стану інших властивостей, не повинна лякати. Просто треба коректно написати код обробки і в одних випадках ігнорувати неправильні звернення, в інших генерувати помилку. Наприклад, у бібліотеці VCL для форми можна одночасно вказати стиль заголовка та його відсутність. Цей парадокс вирішується просто - якщо вікно без заголовка, то стиль заголовка ігнорується.

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

    Список літератури

    Для підготовки даної роботи були використані матеріали з сайту http://karataev.nm.ru/

         
     
         
    Реферат Банк
     
    Рефераты
     
    Бесплатные рефераты
     

     

     

     

     

     

     

     
     
     
      Все права защищены. Reff.net.ua - українські реферати ! DMCA.com Protection Status