
15. Реализация абстракций данных . Функция абстракции. Операции Up и Down.
Реализация абстракций данных
Для реализации типа данных нужно выбирать представление для объектов и реализовать операции в терминах этого представления. Выбранное представление должно предоставлять возможности для довольно простой и эффективной реализации всех операций. Кроме того, если некоторые операции должны выполняться быстро, представление должно предоставлять и эту возможность. Часто представление, обеспечивающее быструю работу некоторых операций, приводит к тому, что другие операции выполняются медленно. В этом случае вы должны использовать несколько различных реализаций одного и того же типа.
Например, возможное представление для объекта intset — это массив целых чисел, где каждое целое число набора intset соответствует элементу массива. Вы должны решить — должен ли каждый элемент набора встречаться в массиве только один раз или же он может встречаться много раз. В последнем случае операция insert будет работать быстрее, однако операции delete и member будут выполняться медленнее. Если операция member используется часто, мы должны остановиться на первом случае.
Заметим, что здесь говорится о двух разных типах: новом абстрактном типе 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