Основы объектно-ориентированного программирования



              

Предусловия и постусловия при наличии динамического связывания - часть 2


Что происходит, когда вводится наследование?

Подпрограмма, клиент, контракт и потомок

Рис. 16.2.  Подпрограмма, клиент, контракт и потомок

Пусть новый класс A' порожден от A и содержит повторное объявление r. Как он может, если вообще может, заменить прежнее предусловие

новым ?, а прежнее постусловие ? - новым
?

Чтобы найти ответ, рассмотрим обязательства клиента. В вызове a1.r цель a1 может - в силу полиморфизма - иметь тип A'. Однако C об этом не знает! Единственным объявлением a1 остается исходная строка

a1: A

где упоминается A, но не A'. На деле C может использовать A', даже если его автор не знает о наличии такого класса. Вызов подпрограммы r может произойти, например, в процедуре C вида:

some_routine_of_C (a1: A) is do ...; a1.r;... end

Тогда при вызове some_routine_of_C из другого класса в нем может использоваться фактический параметр типа A', даже если в тексте клиента C класс A' нигде не упоминается. Динамическое связывание как раз и означает тот факт, что обращение к r приведет в этом случае к использованию переопределенной версии A'.

Итак, может сложиться ситуация, в которой C, являясь только клиентом A, фактически во время выполнения использует версии компонентов класса A'. (Можно сказать, что C - "динамический клиент" A', хотя в тексте C об этом и не говорится.)

Что это значит для C? Только одно - проблемы, которые возникнут, если не предпринять никаких действий. Клиент C может добросовестно выполнять свою часть контракта, и все же в результате он будет обманут. Например,

if a1.

then a1.r end

если a1 полиморфно присоединена к объекту типа A', инструкция вызовет подпрограмму, ожидающую выполнения ? и гарантирующую выполнение

, в то время как клиент получил указание соблюдать
и ожидать выполнения ?. Налицо возможное расхождение во взглядах клиента и поставщика на контракт.




Содержание  Назад  Вперед