Динамично свързване
Фундаментален учебник по основи на обектно-ориентираното програмиране и софтуерното инженерство. Книгата описва подробно основните концепции на обектната технология - класове, обекти, управление на паметта, типизиране, наследяване, универсализация. Много внимание се обръща на проектирането чрез договор и обработката на изключения като механизми, които гарантират коректността и стабилността на софтуерните системи.
Книгата на Бертран Майер обхваща основите на обектно-ориентираното програмиране. Презентацията започва с разглеждане на критериите за качество на софтуерните системи и обосновка как технологията за разработка на обекти може да осигури необходимото качество. Основните понятия на технологията на обекта и съответната нотация възникват в резултат на внимателен анализ и дискусия. Концепцията за клас, централната концепция на обектната технология, е разгледана подробно. Разглеждат се абстрактният тип данни, лежащ в основата на класа, комбинацията от ролята на типа данни и модула от класа и други аспекти на конструирането на класа. Със същия детайл са разгледани обектите и проблемите на управлението на паметта. По-голямата част от книгата е посветена на връзката между класовете – наследяване, универсализация и тяхната роля в изграждането на софтуерни системи. Важна част от книгата е въвеждането на концепцията за договор, описание на технологията за проектиране на договор като механизъм, който гарантира коректността на създаваните програми. Други важни теми от обектното програмиране не са пренебрегнати - скриване на информация, статично типизиране, динамично обвързване и обработка на изключения. Дълбочината на обхващане на засегнатите теми прави книгата на Бертран Майер незаменима за разбирането на основите на обектното програмиране.
Книга: Основи на обектно-ориентираното програмиране
динамиченподвързване
Динамичното свързване ще допълни предефинирането, полиморфизма и статичното типизиране, създавайки основна тетралогия на наследяване.
Използване на правилния вариант
Операциите, дефинирани за всички варианти на полигони, могат да бъдат реализирани по различни начини. Напримерпериметър(периметър ) има различни версии за общи многоъгълници и за правоъгълници, нека наречем тези версииperimeterPOLиperimeterRECT. КласътSQUAREсъщо ще има свой собствен вариант (4 пъти дължината на страната). Това естествено повдига важен въпрос: какво се случва, ако програма, която има различни версии, се приложи към полиморфен обект?
създаване на p.make(.); x := p.периметър
ясно е, че ще се използва версиятаperimeterPOL. Абсолютно същото във фрагмента
създаване на r.make(.); x := r.периметър
ще се използва версиятаperimeterRECT. Но какво ще стане, ако полиморфният обектpе статично деклариран като многоъгълник, но динамично препраща към правоъгълник? Да кажем, че искаме да изпълним фрагмент:
създайте r.make (. ) p := r x := p.perimeter
Правилото за динамично обвързване гласи, чединамичната форма на обекта определя версията на приложената операция. В този случай ще бъдеperimeterRECT.
Разбира се, по-интересен случай възниква, когато не е възможно да се направи извод от програмния текст какъв динамичен типpще има по време на изпълнение. Например какво ще има във фрагмента
-- Изчислете периметъра на фигурата, избрана от потребителя p: МНОГОГОЛНИК . ако избрана_икона = правоъгълна_икона, тогава създайте p.make (. ) elseif selected_icon = триъгълна_икона, тогава създайте p.make (. ) elseif . край . x := p.периметър
или след товаусловно полиморфно присвояванеако . тогава p := r elseif . тогава p := t .; или акоpе елемент от полиморфен масив от полигони, или акоpе формален аргумент с деклариран типPOLYGONна някаква процедура, на която извикващата процедура е подала действителен аргумент от последователен тип?
Тогава, в зависимост от хода на изчислението, динамичният типpще бъдеRECTANGLE, илиTRIANGLE, или други подобни. Няма как да знаем кой от тези случаи ще се случи. Но благодарение на динамичното обвързване не е необходимо да знаете това: каквото и да се случи сp, правилната версия на компонентаperimeterще бъде изпълнена, когато бъде извикан.
Тази способност на операциите да се адаптират автоматично към обектите, към които се прилагат, е една от основните характеристики на OO системите, която е пряко свързана с въпросите за качеството на софтуера, разгледани в началото на книгата. Последствията от него ще бъдат обсъдени по-подробно по-късно в тази лекция.
Динамичното свързване завършва обсъждането на загубата на информация при полиморфизма, което започнахме по-горе. Сега е ясно защо е добре да се губи информация за обект: след присвояване наp := qили извикване наsome_routine (q), в коетоpе формален аргумент, специфичната информация за типа наqсе губи, но ако се приложи операциятаp.polygon_feature, за коятоpolygon_featureима специална версия, приложима къмq, тогава тази версия ще бъде изпълнена.
Напълно приемливо е да изпратите вашите домашни любимци в отдела за отсъстващи домакини, който обслужва всички видове, ако знаете със сигурност, че когато дойде време за ядене, вашата котка ще получи котешка храна, а вашето куче ще получи кучешка храна. |
Отмяна и твърдения
Ако клиент от класPOLYGONизвикаp.perimeter, той очаква да получи стойността на периметъраp, дефинирана от спецификацията на функциятаperimeterв дефиницията на класа. Но сега, благодарение на динамичното обвързване, клиентът може да извика друга програма, отменена в някакъв клас наследник. В класаRECTANGLEзамяната подобрява ефективността и не променя резултата, но какво лошо има в замяната на периметъра, така че новата версия да изчислява, да речем, площ?
Това противоречи на духа на предефинирането. Отмяната трябва да промени изпълнението на процедурата, а не нейната семантика. За щастие твърденията ви позволяват да ограничите семантиката на процедурите. Неформално, основното правило за преодоляване и контрол на динамично обвързване може да се формулира просто: предусловието и постусловието на програмата трябва да се прилагат към всяко нейно предефиниране и, както видяхме, инвариантът на класа трябва автоматично да се прилага към всички негови наследници.
Относно внедряването на динамично обвързване
Човек може да се притеснява, че динамичното свързване е скъп механизъм, изискващ търсене на наследствена графика по време на изпълнение и следователно допълнителни разходи, които се увеличават с дълбочината на графиката.
За щастие, това не е така за добре проектиран (и статично въведен) OO език. Това ще бъде обсъдено по-подробно в края на лекцията, но сега можем да се успокоим с факта, че последствията от динамичното обвързване няма да бъдат значителни за ефективността при работа в правилната среда.