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

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