Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
43
Добавлен:
23.03.2015
Размер:
860.67 Кб
Скачать

15. Реализация абстракций данных . Функция абстракции. Операции Up и Down.

Реализация абстракций данных

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

Например, возможное представление для объекта intset — это массив целых чисел, где каждое целое число набора intset соответствует элементу массива. Вы должны решить — должен ли каждый элемент набора встречаться в массиве только один раз или же он может встречаться много раз. В последнем случае опе­рация insert будет работать быстрее, однако операции delete и member будут выполняться медленнее. Если операция mem­ber используется часто, мы должны остановиться на первом слу­чае.

Заметим, что здесь говорится о двух разных типах: новом абстрактном типе intset, который реализуем, и массиве целых, который используется как представление. Каждая реализация будет иметь два таких типа: абстрактный тип и тип представ­ления (rep type). Предполагается, что с типом представления вы имеете дело только при реализации. Все, что вы можете делать с объектами абстрактного типа, — это применять к ним соответ­ствующие данному типу операции. Соблюдение этого ограниче­ния в языке CLU осуществляется с помощью контроля типов.

Вот пример как реализовать аб­стракции данных на языке CLU

Хотя, конечно, возможно реализовать типы на языках, ко­торые специально не приспособлены для этой цели, более удобно, если тип может быть реализован как отдельный программный модуль. Язык CLU предоставляет такую программную единицу. Эта единица называется кластер. (CLU, отметим, — это первые три буквы слова cluster.) Кластер включает в себя следующее.

1. Заголовок, в котором придаются имена реализуемому типу и операциям. Этот заголовок похож на заголовок в специфика­ции.

2. Определение представления, выбранного в данной реали­зации.

3. Реализации примитивных операций. Дополнительные про­граммы (процедуры и итераторы) также могут быть включены в кластер, но обращаться извне можно только к тем, которым приданы имена в заголовке.

Общий вид кластера

dnarne = cluster is % список имен операций rep = и здесь дается описание представления

% здесь помещаются реализации операций

% если необходимо, здесь могут быть представлены вспомогательные программы

end dnarne

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

гер = array [int ]

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

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

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

up = proc (a: array [int ]) returns (intset)

down == proc (s: intset) returns (array [int])

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

Хотя операции up и down могут появиться, где угодно, среди операций кластера, они в основном используются в одном из двух случаев. В первом случае, когда операция использует в ка­честве аргумента абстрактный объект, для преобразования этого объекта в тип представления используется операция down. Во вто­ром случае, когда операция возвращает заново созданный аб­страктный объект, сразу же перед возвратом для преобразования объекта представления в абстрактный тип используется операция up. Для удобства работы язык CLU предоставляет специально зарезервированное слово cvt. Слово cvt может использоваться как тип аргумента или результата в заголовках операций кластеров. Использование его как типа аргумента указывает, что фактиче­ский аргумент — абстрактного типа, неформальный — типа пред­ставления и что поэтому к фактическому аргументу сразу же после вызова должна быть неявно применена операция down и результирующий объект представления должен быть присвоен формальному аргументу. Когда cvt используется как тип резуль­тата, это означает, что результирующий объект — абстрактного типа, но возвращаемый объект—типа представления и что по­этому прямо перед возвратом к возвращаемому объекту неявно должна быть применена операция up. Слово cvt не добавляет ни­какой функциональности, которая не была бы обеспечена опера­циями up и down. Оно обеспечивает только удобство, которое возникает из возможности довольно просто описывать общие слу­чаи.

Реализации процедуры intset.

intset == cluster is create, insert, delete, member, size, choose rep = array [int]

create = proc ( ) returns (cvt) return (rep$new ( )) end create

insert = proc (s: intset, x: int)

if — member (s, x) then rep$addh (down (s), x) end end insert

delete = proc (s: cvt, x: int) j: int :== getind (s, x) if j <= rep$high (s) then s [j] := rep$top (s) % top возвращает s [high (s)]

rep$remh (s) end end delete

member = proc (s: cvt, x: int) returns (bool) return (getind (s, x) <= rep$high (s)) end member

size = proc (s: cvt) returns (int^ return (rep$size (s)) end size

choose = proc (s: cvt) returns (int)

return (rep$bottom (s)) % bottom возвращает s [low (s) ] end choose

getind = proc (s: rep, x: int) returns (int) i: int : = rep$low (s) while i (= rep$high (s) do if x = s [i] then return (i) end i:=i+ I end return (i) end getind

end intset

Операции up и down

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

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

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

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

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

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