Поліморфізм і заменяемости

У цьому розділі розглядаються два важливих поняття, поліморфізм і заменяемость, які разом складають основу для досягнення того переваги повторного використання коду, яке було коротко згадано в розділі 201 Необхідно відразу зазначити, що ці два поняття фактично являють собою лише різні способи трактування однієї і тієї ж теми Але так чи інакше, почнемо з розгляду поняття поліморфізму

Поліморфізм

На підставі самого визначення успадкування можна зробити висновок, що якщо Т – підтип типу т, то всі оператори, які можуть застосовуватися до значень типу т, є також застосовними до значень типу T . Наприклад, якщо оператор AREA (е) Є застосовним по відношенню до того значення е, яке являє собою еліпс, то застосовним повинен також бути оператор AREA (с), де з являє собою коло Тому слід зазначити, що необхідно ретельно враховувати логічне відмінність між формальними параметрами, в термінах яких визначено даний оператор (разом з їх оголошеними типами), та відповідними фактичними параметрами в конкретному виклику цього оператора (які мають своїми найбільш конкретними типами) Наприклад, оператор AREA визначений в термінах формальних параметрів оголошеного типу ELLIPSE (див розділ 202), але найбільш конкретним типом фактичного параметра у виклику AREA (с) є CIRCLE

Ще раз нагадаємо, що еліпси і кола (щонайменше, в тому вигляді, в якому вони були визначені в розділі 202) мають різні можливі уявлення, як показано нижче

ТУРІ ELLIPSE

POSSREP {А .., В .., CTR ..}

TYPE CIRCLE

POSSREP { R , CTR }

3 Насправді, не існує якихось обгрунтованих причин, за якими всі значення одного і того ж типу повинні були б мати одне і те ж фізичне уявлення Наприклад, одні точки можуть бути фізично представлені за допомогою декартових координат, а інші – за допомогою полярних координат одні температури можуть бути фізично представлені в градусах Цельсія, а інші – в градусах Фаренгейта одні цілі числа можуть бути фізично представлені у вигляді десяткових чисел, а інші – у вигляді двійкових і тд Безумовно, в подібних випадках система повинна мати відомості про те, як перетворюються фізичні уявлення, для того щоб мати здатність реалізовувати оператори присвоювання, порівняння і тд належним чином

Тому допустимо застосування двох різних версій оператора AREA, прихованих від користувача, в одній з яких використовується можливе подання ELLIPSE, а в іншій – можливе подання CIRCLE Ще раз відзначимо, що ця умова є допустимим, але не необхідним Наприклад, код цього оператора стосовно еліпсам може виглядати наступним чином

OPERATOR AREA ( E ELLIPSE ) RETURNS AREA RETURN ( 314159 * THE_A ( E ) * THE_B ( E

) ) END OPERATOR

(Площа еліпса визначається за формулою πаb) Цілком очевидно, що цей код працює правильно, якщо при виклику йому передається окружність замість більш загальної фігури – еліпса, оскільки стосовно до окружності обидва оператора ТНЕ_А І ТНЕ_В повертають радіус r Але програміст, відповідальний за визначення типу CIRCLE, може вирішити з багатьох причин реалізувати іншу версію оператора AREA, яка відноситься тільки до кіл і викликає оператор THE_R замість операторів ТНЕ_А і ТНЕ_В

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

Але слід зазначити, що код для еліпсів, безумовно, буде не застосуємо для кіл, якщо він розроблений в термінах фізичного представлення типу ELLIPSE, a неможливого уявлення, і фізичні подання типів ELLIPSE І CIRCLE різняться Підхід до реалізації операторів в термінах фізичних уявлень взагалі не рекомендуется4 Тому код слід розробляти обачно

Так чи інакше, але якщо оператор AREA не буде повторно реалізований для типу CIRCLE, то має місце ситуація повторного використання коду (тут мова йде про код реалізації оператора AREA)

Примітка Більш важлива різновид ситуації повторного використання коду зустрінеться в наступному підрозділі

Безумовно, що стосується моделі, то не має значення, скільки оудет існувати версій оператора AREA, прихованих від користувача, оскільки з точки зору користувача є лише один оператор AREA, застосовний до еліпсам, а тому, за визначенням, також і до кіл Іншими словами, що стосується моделі, то оператор AREA є поліморфним, а це означає, що він може приймати фактичні параметри різних типів при різних викликах Тому слід зазначити, що подібний поліморфізм є логічним продовженням успадкування, оскільки, якщо передбачено спадкування, то ми зобовязані передбачити поліморфізм, а в іншому випадку не може бути й спадкування

4 Наша власна рекомендація фактично полягає в тому, що доступ до фізичних уявленням повинен бути обмежений тільки тим кодом, в якому реалізується оператори, приписані моделлю (селектори, оператори ТНЕ_ і тд) (Більше того, багато хто з цих операторів на практиці, швидше за все, матимуть реалізації, передбачені в системі)

Отже, ідею поліморфізму як таку не можна назвати такою вже нової, як уже міг помітити читач (фактично ця тема вже коротко розглядалася в розділі 5) Наприклад, у мові SQL давно застосовуються поліморфні оператори (=, +, | | і багато інших) і фактично така ж ситуація виявляється в більшості інших мов Деякі мови навіть дозволяють користувачам визначати свої власні поліморфні оператори наприклад, у мові PL / I такий засіб надається під імям універсальних функцій (ключове слово GENERIC) АЛЕ ВО всіх наведених тут прикладах спадкування як таке відсутнє, оскільки всі ці приклади відносяться до так званого поліморфізму перевантаження (Overloading polymorphism) На відміну від цього, той вид поліморфізму, який виявляється в операторі AREA, НОСИТЬ назву поліморфізму включення (Inclusion polymorphism) на тій підставі, що звязок між (скажімо) окружностями і еліпсами по суті являє собою відношення включення множин [204] З очевидних причин до кінця цієї глави неуточнений термін поліморфізм застосовується для позначення саме поліморфізму включення, якщо явно не вказано інше

Примітка Нижче наведені наочні визначення, що дозволяють краще зрозуміти відмінності між поліморфізмом перевантаження і поліморфізмом включення

■&nbsp&nbsp&nbsp&nbsp Поліморфізм перевантаження означає наявність декількох різних операторів з од ним і тим же імям (при цьому користувач не зобовязаний знати, що рассматривае мие оператори фактично є різними і мають різну семантику – хоча і бажано, щоб їх семантика була досить близькою) Наприклад, в більшості мов перевантаженим є оператор +, причому один опера тор + застосовується для складання цілих чисел, другий оператор + предназна чен для складання раціональних чисел і тд

■&nbsp&nbsp&nbsp&nbsp Поліморфізм включення означає наявність тільки одного оператора, який мо же мати кілька різних версій реалізації, прихованих від користувача (причому користувач не зобовязаний знати, чи дійсно існує кілька версій реа лізації, – ще раз підкреслимо, що для користувача це просто один оператор)

Програмування з використанням поліморфізму

Розглянемо наступний приклад Припустимо, що потрібно розробити програму відображення деякої схеми, що складається з квадратів, кіл, еліпсів і тд Без використання поліморфізму така програма (Представлена ​​у вигляді псевдокоду) виглядатиме приблизно так

FOR EACH x ∈

DIAGRAM CASE

WHEN IS_SQUARE ( X ) THEN CALL DISPLAY_SQUARE ..

; WHEN IS_CIRCLE ( X ) THEN CALL DISPLAY_CIRCLE

END CASE

(Тут передбачається, що передбачені оператори IS_SQUARE, IS_CIRCLE і тд, які можуть застосовуватися для перевірки того, чи відноситься дане значення до зазначеного типу див розділ 206) На відміну від цього, при використанні поліморфізму код стає простішим і набагато більш виразним, як показано нижче

FOR EACH X £ DIAGRAM CALL DISPLAY ( X )

Пояснення У цьому прикладі DISPLAY-поліморфний оператор Версія реалізації оператора DISPLAY, призначена для роботи зі значеннями типу т, задається при

визначенні типу Е і з цього моменту стає відомою системі Тому на етапі

прогону програми при виявленні системою виклику оператора DISPLAY з фактичним параметром х система повинна визначити найбільш конкретний тип х, а потім викликати версію оператора DISPLAY, відповідного цього типу Такий процес називається звязуванням на етапі прогона5 (Run-time binding) Іншими словами, поліморфізм по суті означає, що вирази CASE та оператори CASE, які в іншому випадку повинні були б зявитися у вихідному коді користувальницької програми, стають прихованими від користувача, оскільки ці операції вибору напрямку подальшого продовження програми за допомогою операторів CASE фактично виконує система від імені користувача

Зокрема, заслуговує на увагу те, який вплив чинять описані вище кошти на весь процес супроводження програми Наприклад, припустимо, що в якості ще одного безпосереднього підтипу POLYGON визначено новий тип TRIANGLE і тому на відображуваної схемою тепер будуть зявлятися також і трикутники Без використання поліморфізму кожну програму, яка містить вираз CASE або інші оператори, аналогічні наведеним в даному прикладі, тепер доведеться модифікувати і включити в неї код приблизно в наступній формі

WHEN IS_TRIANGLE ( X ) THEN CALL DISPLAY_TRIANGLE ..

Однак при використанні поліморфізму подібні модифікації вихідного коду не потрібні

Під враженням прикладів, подібних до наведеного вище, поліморфізм іноді характеризують таким метафоричним виразом, як спосіб викликати новий код з

допомогою старого коду ; це означає, що програма р фактично набуває можливість викликати деяку версію деякого оператора, яка навіть ще не існувала (мається на увазі версія) до часу написання програми Р Тому в даному випадку показаний інший (і більше важливий) спосіб повторного використання коду, в якому зовсім однакова програма може застосовуватися, крім усього іншого, і для обробки даних типу т (ще раз повторюємо), навіть не існувало до часу написання програми Р

Замінність

Як вже було сказано, поняття заменяемости по суті являє собою просто поняття поліморфізму, що розглядається трохи з іншої точки зору Наприклад, було показано, що якщо оператор AREA (е), де е – еліпс, є допустимим, то повинен бути також допустимим оператор AREA (с), де с – окружність Іншими словами, в будь-якому місці, де система допускає наявність еліпса, можна завжди замінити його колом Більш загальне формулювання цього принципу полягає в тому, що в будь-якому місці, де система допускає використання значення типу т, його завжди можна замінити значенням типу T , де Т – підтип типу т Цей принцип називаєтьсяпринципом заменяемости значень

5 Безумовно, що застосування процесу звязування на етапі прогону належить до завдань реалізації, а не до завдань визначення моделі Це – ще одна з тих завдань реалізації, важливість яких читач повинен певною мірою оцінити, щоб правильно зрозуміти всю концепцію спадкоємства

Глава 20 Спадкування типів783

Зокрема, слід зазначити, що з цього принципу випливає такий висновок: якщо деяке відношення r має атрибут А з оголошеним типом ELLIPSE, то деякі значення атрибута А щодо r можуть належати до типу CIRCLE, а не просто до типу ELLIPSE Аналогічним чином, якщо деякий тип т має можливе подання, що включає компонент з оголошеного типу ELLIPSE, то для деяких значень v типу т виклик оператора ТНЕ_С (v) може повертати значення типу CIRCLE, а не просто типу ELLIPSE

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

Джерело: Дейт К Дж, Введення в системи баз даних, 8-е видання: Пер з англ – М: Видавничий дім «Вільямс», 2005 – 1328 с: Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*