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

В описании STACK[G] именем G обозначен произвольный, не определяемый тип. G называется формальным родовым параметром для типов элементов АТД STACK, а сам STACK называется родовым или универсальным АТД. Механизм, допускающий такие параметризованные спецификации, известен как универсализация, мы уже сталкивались с аналогичным понятием в обзоре конструкций пакетов.

Можно писать спецификации АТД без параметризации, но ценой будут неоправданные повторения. Кроме того, возможность повторного использования желательна не только для программ, но и для спецификаций! Благодаря механизму универсализации, можно выполнять параметризацию типов в явном виде, выбрав для параметра некоторое произвольное имя (здесь - G), представляющее переменную для типа элементов стека.

В результате такой АТД как STACK - это не просто тип, а скорее образец типа. Для получения непосредственно используемого типа стека нужно определить тип элементов стека, например ACCOUNT, и передать его в качестве фактического родового параметра, соответствующего формальному параметру G. Поэтому, хотя сам по себе STACK это образец типа, обозначение STACK[ACCOUNT] задает полностью определенный тип. Про такой тип, полученный с помощью передачи фактических параметров типов в родовой тип, говорят, что он порожден из общего по образцу.

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

Как показывает этот пример, предыдущее определение "экземпляра" нуждается в некоторой модификации. Строго говоря, конкретный стек является экземпляром не типа STACK (который, как мы заметили, является скорее образцом типа, а не типом), а некоторого типа, порожденного типом STACK, например, образцом типа STACK[ACCOUNT]. Тем не менее, нам удобно и далее говорить об экземплярах типа S и других образцов типов, понимая при этом, что речь идет об экземплярах порожденных ими типов.

Аналогично, не очень правильно говорить о типе STACK как об АТД: правильный термин в этом случае - "образец АТД". Но для простоты в данном обсуждении мы будем и далее, если это не приведет к путанице, опускать слово "образец".

Это отличие перенесется и на ОО-проектирование и программирование, но там нам не потребуется два разных термина:

[x]. Основным понятием будет класс, который может иметь родовые параметры.

[x]. Описание реальных данных требует типов. Класс без параметров является также и типом, но класс с параметрами - только образец типа. Чтобы получить конкретный тип из такого класса, нужно передать ему фактические параметры типов, точно так, как мы это делали при получении АТД STACK[ACCOUNT], исходя из образца АТД STACK[G].

<p>Перечисление функций</p>

Вслед за разделом ТИПЫ идет раздел ФУНКЦИИ, в котором перечисляются операции, применяемые к экземплярам данного АТД. Как уже говорилось, эти операции будут главными компонентами определения типа, с их помощью описывается, что могут предложить его экземпляры, а не то, чем они являются.

Ниже приведен раздел ФУНКЦИИ для абстрактного типа данных STACK. Если вы разработчик ПО, то этот стиль описания вам знаком: строки этого раздела напоминают декларации типизированных языков программирования таких, как Pascal или Ada. Строка для операции new похожа на объявление переменной, остальные - на заголовки процедур.

Функции

[x].put: STACK [G] × G STACK [G]

[x].remove: STACK [G] STACK [G]

[x].item: STACK [G] G

[x].empty: STACK [G] BOOLEAN

[x].new: STACK [G]

В каждой строке вводится определенная математическая функция, моделирующая соответствующую операцию над стеком. Например, функция put представляет операцию, которая вталкивает элемент на вершину стека.

Почему функции? Большая часть программистов не посчитает такую операцию как put функцией. Когда во время работы программной системы операция put применяется к стеку, она, как правило, изменяет этот стек, добавляя к нему элемент. Вследствие этого в приведенной выше классификации операций put была "командой" - операцией, которая может модифицировать объекты. (Две другие категории операций - это конструкторы и запросы).

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

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