Динамічне зв’язування

perimeter

Фундаментальний підручник з основ об'єктно-орієнтованого програмування та інженерії програм. У книзі докладно викладаються основні поняття об'єктної технології – класи, об'єкти, управління пам'яттю, типізація, наслідування, універсалізація. Велика увага приділяється проектуванню за контрактом та обробкою винятків як механізмам, що забезпечують коректність і стійкість програмних систем.

У книзі Бертрана Мейєра розглядаються засади об'єктно-орієнтованого програмування. Виклад починається з розгляду критеріїв якості програмних систем та обґрунтування того, як об'єктна технологія розробки може забезпечити необхідну якість. Основні поняття об'єктної технології та відповідна нотація з'являються як результат ретельного аналізу та обговорень. Докладно розглядається поняття класу – центральне поняття об'єктної технології. Розглядається абстрактний тип даних, що лежить в основі класу, поєднання класом ролі типу даних та модуля та інші аспекти побудови класу. Так само докладно розглядаються об'єкти та проблеми управління пам'яттю. Більшість книги приділено відносинам між класами – успадкування, універсалізації та його ролі у побудові програмних систем. Важливу частину книги становить запровадження поняття договору, опис технології проектування за контрактом, як механізму, що забезпечує коректність створюваних програм. Не залишилися без уваги й інші важливі теми об'єктного програмування – приховування інформації, статична типізація, динамічне зв'язування та обробка винятків. Глибина охоплення тем робить книгу Бертрана Мейєра незамінною для розуміння основ об'єктного програмування.

Основи об'єктно-орієнтованого програмування

Динамічнезв'язування

Динамічне зв'язування доповнить перевизначення, поліморфізм та статичну типізацію, створюючи базову тетралогію успадкування.

Використання правильного варіанту

Операції, визначені всім варіантів багатокутників, можуть реалізовуватися по-різному. Наприклад,perimeter(периметр ) має різні версії для загальних багатокутників і прямокутників, назвемо ці версіїperimeterPOLіperimeterRECT. У класуSQUAREтакож буде свій варіант (помножена на 4 довжина сторони). При цьому природно виникає важливе питання: що станеться, якщо програма, яка має різні версії, буде застосована до поліморфної сутності?

create p.make (.); x := p.perimeter

ясно, що буде використана версіяperimeterPOL. Так само у фрагменті

create r.make (.); x := r.perimeter

буде використана версіяperimeterRECT. Але що, якщо поліморфна сутність статично оголошена як багатокутник, а динамічно посилається на прямокутник? Припустимо, що потрібно виконати фрагмент:

create r.make (. ) p := r x := p.perimeter

Правило динамічного зв'язування стверджує, що версію застосовуваної операції визначаєдинамічна форма об'єкта. В даному випадку це будеperimeterRECT.

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

-- Обчислити периметр фігури обраної користувачем p: POLYGON . if chosen_icon = rectangle_icon then create p.make (. ) elseif chosen_icon = triangle_icon then create p.make (. ) elseif . end . x:=p.perimeter

або післяумовного поліморфного присвоєнняif. then p := r elseif . then p := t .; або якщоpє елементом поліморфного масиву багатокутників, або якщоpє формальним аргументом з оголошеним типомPOLYGONдеякої процедури, якій процедура, що її викликала, передала фактичний аргумент узгодженого типу?

Тоді залежно від ходу обчислення динамічним типомpбудеRECTANGLE, абоTRIANGLE, або т.п. У нас немає жодного способу дізнатися, який із цих випадків матиме місце. Але, завдяки динамічному зв'язуванню, цього не потрібно знати: що б не сталося зp, при виклику буде виконано правильний варіант компонентаperimeter.

Ця здатність операцій автоматично пристосовуватися до тих об'єктів, до яких вони застосовуються, є однією з головних особливостей ГО-систем, що безпосередньо відноситься до питань якості ПЗ, що обговорюються на початку книги. Її наслідки будуть детальніше розглянуті далі у цій лекції.

Динамічне зв'язування дозволяє завершити розпочате вище обговорення аспектів, пов'язаних із втратою інформації при поліморфізмі. Тепер стало зрозуміло, чому не страшно втратити інформацію про об'єкт: після наданняp := qабо викликуsome_routine (q), в якомуpбув формальним аргументом, втрачається специфічна інформація про типq, але якщо застосовується операціяp.polygon_feature, для якоїpolygon_featureмає спеціальну версію, застосовну доq, то виконуватиметься саме ця версія.

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

Перевизначення та затвердження

Якщо клієнт класуPOLYGONвикликаєp.perimeter, він очікує отримати значення периметраp, визначене специфікацією функціїperimeterу визначенні цього. Але тепер завдяки динамічному зв'язуванню клієнт може викликати іншу програму, перевизначену в деякому класі-нащадку. У класіRECTANGLEперевизначення покращує ефективність і змінює результат, але що завадило б перевизначити периметр те щоб нова версія обчислювала б, скажімо, площа?

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

Про реалізацію динамічного зв'язування

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

На щастя, це не так у разі добре спроектованої (і статично типізованої) ГО-мови. Більш детально це буде обговорюватися наприкінці лекції, але ми можемо вже зараз заспокоїти себе тим, що наслідки динамічного зв'язування не будуть суттєвими для ефективності роботи у відповідному оточенні.