Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
AlgStr / Библиотека / ЛЕКЦИИ / PZ00 / Яременеко.doc
Скачиваний:
38
Добавлен:
23.03.2015
Размер:
173.57 Кб
Скачать

Операции up и down

Полезно представлять себе операцию up как окружение объекта типа представления непроницаемой заслонкой. Тому, кто использует операцию up, сквозь эту заслонку не видно представ­ления. Значение объекта можно исследовать только вызовом при­митивных операций, соответствующих типу объекта. Например, пользователь не видит массива, который представляет набор intset, но может сказать, какие элементы имеются в наборе, и может добавлять или удалять элементы, обращаясь к соответ­ствующим операциям.

Операция down производит обратное действие по отношению к up — она убирает заслонку. Если бы для пользователя имелась возможность обращаться к down, то ему было бы доступно кон­кретное представление абстрактного объекта и выгоды абстрак­ции данных были бы утеряны. Поэтому язык CLU позволяет использовать операцию down только в кластере, который реали­зует объект.

Чтобы избежать возникновения фальшивых объектов, огра­ничивается также и использование операции up. Если бы эту операцию можно было использовать вне определяющего кластера, было бы возможно создавать объекты, которые выглядели как объекты типа, но которые при передаче их операциям кластера в качестве аргумента имели бы другое, чем ожидается, пред­ставление, что приводило бы к всевозможным очень неприятным ошибкам. Поэтому, чтобы использование абстракций данных было выгодно, ограничение сферы применения операций up и down необходимо.

Как уже говорилось, если операция down используется внутри кластера, то она убирает заслонку и представление объекта ста­новится видимым. Однако это представление есть просто другой абстрактный объект, и он защищен заслонкой, сконструирован­ной его собственной реализацией, которая может быть либо оп­ределенным пользователем кластером, либо частью реализации языка CLU. Реальное представление объекта снова недоступно, но информация об объекте может быть получена при помощи операций. Так, внутри кластера intset нам недоступна внутрен­няя структура массива, который реализует intset, но вы можете исследовать и изменять интересующую нас информацию, исполь­зуя операции работы с массивом.

Для операций up и down (и следовательно, для cvt) не гене­рируется никакого объектного кода. Они лишь информируют компилятор о том, что способ рассмотрения объекта изменился. Компилятор использует эту информацию для контроля типов. Так как контроль типов производится во время компиляции, эта информация не нужна при выполнении, хотя она и может быть по­лезна для отладки.

Функция абстракции

Любая реализация абстракции данных должна определять, как представляются объекты, принадлежащие к этому типу. Выбирая представление, тот, кто занимается реализацией, учи­тывает связь между объектами представления и абстрактными объ­ектами. Предполагается, что определенные объекты представле­ния будут соответствовать, определенным абстрактным объектам.

Эта взаимосвязь может быть определена функцией, которая называется функцией абстракции. Эта функция отображает объ­екты представления в абстрактные объекты:

Здесь А обозначает набор абстрактных объектов. Для каж­дого объекта представления r, А(r) является абстрактным объ­ектом аA, который представляет r.

А: repА

Рис. 1. Пример функции абстракции.

Например, функция абстракции для реализации intset ото­бражает массив array[int] в набор intset. На рис.1 показаны отображения некоторых точек функции абстракции. Заметим, что А может отображать различные элементы в один, т.е. различным объектам представления может соответствовать один и тот же абстрактный элемент из A. Например, [1: 1, 2] и [1: 2, 1] представ­ляют один набор intset {l, 2}. В том, что функция абстракции часто отображает различные элементы в один, нет ничего удиви­тельного, так как процесс абстракции отбрасывает не относя­щуюся к делу информацию. В этом примере такая информация — это расположение элементов в массиве.

Функция абстракции – это важнейшая информация о реали­зации. Она определяет конкретное представление, т.е. то, каким образом объекты представления реализуют абстрактные объ­екты. Эта функция должна быть обязательно представлена в комментариях реализации. Описывая функцию реализации, мы иногда сталкиваемся с проблемой, связанной с тем, что, если спецификация типа неформальная, область изменения функции абстракции не может быть точно определена. Сейчас мы будем преодолевать эту проблему с помощью неформального описания «типичного» абстрактного объекта.

Для определения функции абстракции прежде всего опреде­ляем типичный элемент абстрактного типа. Это дает нам воз­можность говорить об абстрактных объектах. Затем можем оп­ределить функцию абстракции в терминах этого типичного объ­екта. Например, для наборов intset вы можете дать следующее описание:

Типичный набор intset есть {х1, ... хn}

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

/*Функция абстракции есть

А(r) = {r[i] | low(r) i high(r)},

*/

где {x | p(x)} есть набор всех таких х, что р(х) имеет значение true.

В качестве другого примера рассмотрим полиномы. Мы ре­шаем представлять полином массивом, в котором i-й элемент содержит i-й коэффициент, если этот коэффициент не относится к нулевым коэффициентам справа или слева от значащих чле­нов полинома. Это представление описываем следующим образом:

/*Типичный полином есть: c0 + c1x + c2x2+ ...

Функция абстракции для коэффициента с1 есть

ci = г [i], если low(r)  i  high (r)

= 0 в противном случае

*/

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

Функция абстракции, в частности, удобна тем, что устраняет двусмысленности в интерпретации представления. Например, предположим, что с помощью массивов мы реализуем стеки. Мы можем выбирать, каким образом увеличивать массив, когда в стек добавляется новый элемент. Этот наш выбор будет отражен в функции абстракции. Если вы решаете увеличивать старший ин­декс массива и по этому индексу записывать элемент, то функция абстракции будет следующая:

/*Типичный стек – это последовательность [е1,...,еn], где

еn – элемент со старшим индексом

Функция абстракции есть

А(г) = [r[low (r)], ..., r [high (r)]]

Если вы решаете уменьшать младший индекс и по этому ин­дексу записывать элемент, то

А(r) = [r[high(r)], ..., r[low(r)]]

*/

Заметим, что реализации стеков, о которых только что го­ворилось, используют одно и то же представление, которое интер­претируется, однако, по-разному.

Пример функции абстракции для стека

╔════════════════════════════════════════════════════════╗

║ Дескриптор стека REP (Представление стека) ║

║ ┌────────────┐ ========================= ║

S1─────╫─>│ Size │ ║

║ ├────────────┤ ║

║ │ TopInd │ ║

║ ├────────────┤ ║

║ │ PBody │ ║

║ └─────┼──────┘ ║

║ │ ║

║ ┌─────┼─────────────────────────────────────────────┐ ║

║ │ │ Тело стека │ ║

║ │ │ ┌───────────┐ │ ║

║ │ │ Size │-----------│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ ...│-Свободно--│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ │-----------│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ TopInd │///////////│ Вершина │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ ...│///////////│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ 3 │/Заполнено/│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ 2 │///////////│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ └────────> 1 │///////////│ │ ║

║ │ └───────────┘ │ ║

║ │ ////////////////////// │ ║

║ │ //// Дно стека //// │ ║

║ └───────────────────────────────────────────────────┘ ║

╚════════════════════════════════════════════════════════╝

Соседние файлы в папке PZ00