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

4.6.3.Сохранение инварианта представления

Для того чтобы продемонстрировать корректность реализа­ции типа, мы должны, в частности, показать, что инвариант пред­ставления сохраняется для всех законных объектов представ­ления. Мы можем сделать это следующим образом. Прежде всего мы покажем, что инвариант сохраняется для объектов, возвра­щаемых операциями (как, например, операцией poly$create), которые возвращают объект типа, но не имеют аргументов типа. Для всех других операций мы можем предположить, что при их вызове инвариант сохраняется для всех аргументов, являющихся объектами типа; тогда мы должны показать, что он сохраняется при возврате как для аргументов типа, так и для возвращаемых объектов типа.

Например, реализация набора intset(рис. 4.5)имеет инва­риант

%Для всех целых i, j,таких, что low (r) i < j bigh (r) % r [i]~=r lj]

Операция intset$createотвечает этому инварианту потому, что заново созданный массив пуст. Операция memberтакже сохраняет этот инвариант, так как мы знаем, что инвариант сох­раняется для аргумента sи что эта операция не модифицирует s. Операция insertтакже сохраняет инвариант, так как

1)инвариант сохраняется для ее аргумента sпри обращении;

2)при вызове операции memberиз операции insertинвариант сохраняется потому, что он сохраняется в операции member;и

3)операция insertдобавляет х к s,только если выражение^member (s,х) имеет значение true;следовательно, так как на­бор sудовлетворяет инварианту при вызове, он также удовлетво­ряет инварианту после добавления к нему х.

В качестве второго примера рассмотрим реализацию поли­номов poly,представленную на рис. 4.7.Вспомним, что инва­риант есть

% low (r) Ss О

% & if empty (s) then high (r) == 0 % else г How (r) ] ~ = 0 & г [high (г) I ~ == 0

Операция poly$createсохраняет инвариант потому, что она создает нулевой полином. Операция millсохраняет инвариант потому, что

1)при вызове инвариант сохраняется для р и q;

2)случай, когда р или q —нулевой полином, распознается и создается соответствующее представление; и

3)в противном случае ни р, ни qне содержат нулей ни в стар­шем, ни в младшем члене; следовательно, ни младший элемент воз­вращаемого массива (bottom(р)* bottom (q)),ни старший эле­мент (top(р)* top (q))не может быть нулем.

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

4.5.4.Изменяемые представления

Изменяемость (или неизменяемость) —это свойство абстрак­ции, которое должно сохраняться реализацией. Изменяемые абстракции должны иметь изменяемые представления, иначе будет невозможно обеспечить требуемую изменяемость. Однако неизменяемые абстракции не обязательно должны иметь неизме­няемые представления. Например, полиномы неизменяемы, но имеют изменяемое представление. Изменяемые представления приемлемы, если модификации, сделанные в представлении, не могут быть замечены пользователями абстракций.

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

гер =• record lnum, denom: int]

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

%типичное рациональное число есть n/d %Функция абстракции есть%А (г) = r.num/r.denom

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

%Инвариант представления есть% r.denom >О

Давайте также решим находить сокращенную форму при про­верке двух рациональных чисел на равенство. Это мы можем сделать, используя процедуру gcd.

gcd = proc (n, d: int) returns (int) requires nи dдолжны быть положительнымиeffectsВозвращает макс. общий делитель nи d.

Реализация операции equalпредставлена на рис. 4.9.Од­нажды найденные, сокращенные формы записываются в представ­ление, так как это ускоряет работу при последующих обраще­ниях к операции equal.

rep == record [nurn, denom: int] equal == proc (rl, r2: cvt) returns (bool) if rl.nurn =: 0 then return (r2.niim = 0) elseif r2.niim == 0 then return (false) end reduce (rl) reduce (r2)

return (rl.num == r2.num cand rl.denom = r2.denom) end equal

% reduce —внутренняя программа, приводящая ее аргумент к сокращенной

%формеreduce proc (r: rep) g: int :== gcd (in1$abs (r.num), r.denom) r.num :== r.num/g r.denom := r.denom/g etid reduce Рис, 4.9.Благоприятный побочный эффект.

Модификация представления, осуществляемая операцией equal, —благоприятный побочный эффект. Такие побочные эф­фекты часто используются для улучшения эффективности. Они возможны, если функция абстракции отображает различные эле­менты в один, так как тогда имеется много объектов представле­ния, которые представляют один и тот же абстрактный объект. Иногда полезно внутри реализации переходить от одного такого объекта представления к другому. Такой переход законен, так как новое представление соответствует тому же самому абстракт­ному объекту.

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