(норма разности матриц m1 и m2), а также функцию infix '*', результатом которой является произведение двух матриц. One - единичная матрица.

Как человек негордый, летом я приглашу программиста, и он перепишет мою подпрограмму invert, используя более удачный алгоритм, лучше аппроксимирующий результат и допускающий меньшее значение epsilon (как повторное объявление, эта запись синтаксически некорректна:

require

epsilon >= 10 ^ (-20)

...

ensure

((Current * inverse) |-| One) <= (epsilon / 2)

Автор новой версии достаточно умен, чтобы не переписывать MATRIX в целом. Изменения коснутся лишь нескольких подпрограмм. Они будут включены в состав порожденного от MATRIX класса NEW_MATRIX.

Если повторное объявление содержит новые утверждения, они должны иметь иной синтаксис, нежели приведенный выше. Правило появится чуть позднее.

Изменения, внесенные в утверждения, удовлетворяют правилу повторного объявления: новое предусловие epsilon >= 10 ^ (-20) слабее исходного epsilon >= 10 ^ (-6), новое же постусловие сильнее сформулированного вначале.

Вот как все должно происходить. Клиент исходного класса MATRIX запрашивает расчет обратной матрицы именно у него, но на деле - ввиду динамического связывания - вызывает реализацию класса NEW_MATRIX. Тот же клиент может иметь в своем составе подпрограмму

some_client_routine (m1: MATRIX; precision: REAL) is

do

... ; m1.invert (precision); ...

-- Возможен вызов версии как MATRIX, так и NEW_MATRIX

end

которой один из его собственных клиентов передает первый параметр типа NEW_MATRIX.

NEW_MATRIX должен воспринимать и корректно обрабатывать любой вызов, который принимается его предком. Используя более слабое предусловие и более сильное постусловие, мы корректно обработаем все обращения клиентов MATRIX и предложим своим клиентам решение, лучше прежнего.

При усилении предусловия invert, например, epsilon >= 10 ^ (-5), вызов, корректный для класса MATRIX, мог стать теперь некорректным. При ослаблении постусловия возвращаемый результат стал бы хуже, чем гарантируемый для MATRIX.

Устранение посредника

Последний комментарий указывает на весьма интересное следствие правила Утверждений Переобъявления. В общей схеме

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

утверждения γ и , введенные при повторном объявлении, предпочтительнее для клиентов, если они отличаются от и β (предусловия - более слабые, постусловия - более сильные). Но клиент класса A, использующий A' благодаря полиморфизму и динамическому связыванию, не может в полной мере воспользоваться более выгодным контрактом, ибо единственный контракт клиента заключен с классом A.

Воспользоваться преимуществом нового контракта можно лишь став непосредственным клиентом A' (пунктирная связь с вопросительным знаком на рисунке 16.3), как в случае:

a1: A'

...

if a1.γ then a1.r end

check a1. end -- постусловие выполняется

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

Компромисс ясен. Клиент класса MATRIX должен обеспечивать выполнение исходного (более сильного) предусловия, а в ответ вправе ожидать выполнения исходного (более слабого) постусловия. Даже если его запрос динамически подготовлен к обслуживанию классом NEW_MATRIX, воспользоваться новыми возможностями - большей толерантностью входа и большей точностью выхода - ему никак не удастся. Для обращения к улучшенной спецификации клиент должен объявить матрицу типа NEW_MATRIX, тем самым, потеряв доступ к иным порожденным от MATRIX реализациям, не являющимся производными классами самого NEW_MATRIX.

Субподряды

Правило Утверждения Переобъявления великолепно сочетается с теорией Проектирования по Контракту.

Мы видели, что утверждения подпрограммы описывают связанный с ней контракт, в котором клиент гарантирует выполнение предусловия, получая право рассчитывать на истинность постусловия; для поставщика все наоборот.

Наследование совместно с повторным объявлением и динамическим связыванием приводит к созданию субподрядов. Приняв условия контракта, вы не обязаны выполнять его сами. Подчас вы знаете кого-то еще, способного сделать это лучше и с меньшими издержками. Так происходит, когда клиент запрашивает подпрограмму из MATRIX, но благодаря динамическому связыванию

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату