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

count: INTEGER is

-- Число элементов

deferred

end

index: INTEGER is

-- Положение курсора

deferred

end

item: G is

-- Элемент в позиции курсора

deferred

end

feature - Отчет о статусе

after: BOOLEAN is

-- Курсор за последним элементом?

deferred

end

before: BOOLEAN is

-- Курсор перед первым элементом?

deferred

end

feature - Сдвиг курсора

forth is

-- Передвинуть курсор на одну позицию вперед.

require

not after

deferred

ensure

index = old index + 1

end

... Другие компоненты ...

invariant

non_negative_count: count >= 0

offleft_by_at_most_one: index >= 0

offright_by_at_most_one: index <= count + 1

after_definition: after = (index = count + 1)

before_definition: before = (index = 0)

end

Здесь инвариант выражает соотношения между разными запросами. Первые два предложения утверждают, что курсор может выйти за границы множества элементов не более чем на одну позицию слева или справа.

Рис. 14.10.  Позиции курсора

Два последних предложения инварианта можно также представить в виде постусловий: ensure Result = (index = count + 1) для after и ensure Result = (index = 0) для before. Такой выбор всегда возникает при выражении свойств, включающих только запросы без аргументов. Я предпочитаю использовать предложения инварианта, рассматривая такие свойства как глобальные свойства класса, а не прикреплять их к конкретному компоненту.

Утверждения о forth точно выражают то, что должна делать эта процедура: передвигать курсор на одну позицию. Поскольку курсор должен оставаться в пределах списка элементов плюс две позиции "меток" слева и справа, то применение forth требует выполнения условия not after, а результатом будет, как сказано в постусловии, увеличение index на один.

Вот другой пример - наш старый друг стек. Нашей библиотеке потребуется общий класс STACK [G], который будет отложенным, так как он должен покрывать всевозможные реализации. Его собственные потомки, такие как FIXED_STACK и LINKED_STACK, будут описывать конкретные реализации. Одной из отложенных процедур класса STACK является put:

put (x: G) is

-- Поместить x на вершину.

require

not full

deferred

ensure

not_empty: not empty

pushed_is_top: item = x

one_more: count = old count + 1

end

Булевские функции empty и full (также отложенные на уровне STACK) выражают свойство стека быть пустым и заполненным.

Только с помощью утверждений отложенные классы достигают своей полной силы. Как уже отмечалось (хотя детали появятся через две лекции), предусловия и постусловия применимы ко всем переопределениям процедуры. Это особенно важно в отложенном случае: в нем такие утверждения будут ограничивать все допустимые реализации. Таким образом, приведенная спецификация ограничивает все варианты put в потомках класса STACK.

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

В конце этой лекции мы вновь обратимся к отложенным классам и исследуем глубже их роль в процессе ОО-анализа, проектирования и реализации.

<p>Способы изменения объявлений</p>

Возможность изменить объявление компонента - переопределить или дать его реализацию - обеспечивает гибкость и последовательное проведение разработки. Имеется еще два метода, усиливающих эти качества:

[x]. Возможность изменить объявление функции на атрибут.

[x]. Простой способ сослаться на первоначальную версию в теле нового определения.

<p>Повторное объявление функции как атрибута</p>

Повторные объявления позволяют активно применять один из центральных принципов модульности - принцип Унифицированного Доступа (Uniform Access).

Перейти на страницу:

Похожие книги