"Запись" - это имя объекта типа "связи" (объекта сеть(в_узле).связан), локальное для процедуры "переписать". Общий вид ОБЪЯВЛЕНИЯ ПРОЦЕДУРЫ:

<спецификация процедуры> is

<локальные объявления>;

begin

<операторы>;

end процедуры;

Оборот for j in <диапазон> - это ОБЪЯВЛЕНИЕ УПРАВЛЯЮЩЕЙ ПЕРЕМЕННОЙ ЦИКЛА, область действия которой от объяв­ления до конца цикла. Внутри БАЗИСНОГО ЦИКЛА (от loop до end loop) j считается постоянной. Если диапазон пуст (это бывает, когда его правая граница меньше левой), базисный цикл не выпол­няется ни разу. Иначе он выполняется при всех последовательных значениях j из указанного диапазона, если только выполнение всего оператора цикла не будет досрочно завершено оператором выхода (exit).

В нашем случае все имена узлов из массива "узлы" с индексами от "после+1" до "число" перемещаются на позиции с предыдущим индексом. В результате массив "узлы" содержит все старые связи, кроме вычеркнутой, а их общее количество предварительно скорректировано (уменьшено на 1).

Шаг 3.7. Содержательный эффект процедуры "связать" также очевиден: она применима к включенным в сеть узлам; после ее при­менения узлы считаются связанными.

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

НЕ нашли? Не то? Что вы ищете?

По-прежнему не будем заботиться о диагностике ошибок, когда связей оказывается слишком много (больше макс_связей). Но если два узла просят связать вторично, то будем такой запрос игнориро­вать. Следует учесть также, что требование связать узел с самим собой вполне законно.

procedure связать (X, Y: in узел) is

begin

if not есть_связь(Х, Y) then

установить_связь(Х, Y);

if X /= Y then

установить_связь(У, X);

end if;

end if;

end связать;

Мы ввели вспомогательную функцию есть_связь с очевидным эф­фектом (возможно, ее полезно и пользователю предоставить) и вспо­могательную процедуру установить_связь, которая призвана вносить изменения в массив "узлы" своего первого аргумента. (Ключевое слово not - это знак отрицания (унарная логическая операция)).

Продолжим детализацию.

function есть_связь(Х, Y : узел) return BOOLEAN is

запись : связи renames сеть(X).связан;

begin

for i in 1..запись. число loop

if запись. узлы (i) = Y then

return true;

end if;

end loop;

return false;

end есть_связь;

procedure установить_связь(откуда, куда : in узел) is

запись : связи renames сеть(откуда).связан;

begin

запись. число := запись. число+1;

запись. узлы(запись. число) := куда;

end установить_связь;

Таким образом, количество связей увеличивается на единицу и в качестве последней связи записывается имя узла "куда".

Вопрос. Нельзя ли переименование указать вне процедур и функций, чтобы не повторять его?

Подсказка. В переименовании участвуют динамические параметры.

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

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

package body управление_сетью is

type запись_об_узле is

record

включен : BOOLEAN : = false;

связан: связи;

end record;

сеть : array (узел) of запись_об_узле;

function узел_есть(Х : узел) return BOOLEAN is

……

function все_связи(Х : узел) return связи is

……

procedure вставить (X : in узел) is

……

procedure переписать(в_узле : in узел, после : in индекс_узла)

……

procedure чистить(связь : узел, в_узле:узел) is

……

procedure удалить(Х : in узел) is

……

function есть_связь(Х, Y : узел) return BOOLEAN is

.…..

procedure установить_связь(откуда, куда : in узел) is

……..

procedure связать (X, Y : in узел) is

……..

end управление_сетью;

Подчеркнем, что тип запись_об_узле, объект "сеть", процедуры "переписать", "чистить", "установить_связь", функция "есть_связь" недоступны пользователю, так как объявлены в теле, а не в спецификации пакета.

Третий шаг детализации завершен. Осталась прокомментировать полученный результат.

2.7. Принцип раздельного определения, реализации и использования услуг (принцип РОРИУС)

Итак, мы написали три сегмента: спецификацию пакета управление_сетью, процедуру построение_сети и тело пакета управление_сетью. Важно понимать роли этих сегментов в жизненном цикле программы.

В них воплощен принцип раздельного определения, реализации и использования услуг (РОРИУС). По существу, это рациональное применение абстракции на различных этапах проектирования.

Проектируя определение пакета, отвлекаемся от деталей его возможного использования и вариантов реализации.

Проектируя использование пакета, отвлекаемся от деталей определения и тем более реализации.

Проектируя реализацию, отвлекаемся от несущественного (с точки зрения реализации) в определении и использовании.

Упражнение. Приведите конкретные примеры деталей, несущественных при определении, реализации и использовании соответственно.

Каждая названная абстракция (определение, использование, реализация) представлена своим материальным воплощением - отдельным модулем. Ведь каждый из трех сегментов является модулем - законченным продуктом интеллектуальной деятельности в том смысле, что его можно записать в библиотеку и (при наличии документации) использовать без помощи автора и без жесткой связи с остальными модулями.

Три наших модуля, однако, не являются полностью независимыми. Центральным служит, конечно, модуль определения, т. е. спецификация пакета. Оставляя спецификацию неизменной, можно выбирать варианты реализации (тело пакета), не заставляя изменять использование (процедуры, аналогичные процедуре "построение_сети"). И это только благодаря тому, что реализация защищена от несанкционированного доступа при использовании - из процедуры построение_сети нельзя непосредственно добраться, например, до массива "сеть" и нарушить дисциплину его эксплуатации операциями пакета. С другой стороны, никакое изменение реализации (согласованное со спецификацией и содержательным внешним эффектом объявленных услуг) не в состоянии повлиять на какие-либо характеристики использованиия, кроме ресурсоемкости (расхода времени, памяти и других ресурсов). Наконец, можно строить произвольные, одновременно существующие и развивающиеся по-разному использующие модули, не тратя ресурсов на однажды уже определенные и реализованные услуги.

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

2.8. Принцип защиты абстракций

Кроме РОРИУС, в связи с только что отмеченной потребностью необходимо указать на еще один важный принцип – принцип защиты абстракций (от разрушения). Одно из его проявлений в Аде - доступ к телу пакета исключительно через имена, объявленные в спецификации. Именно благодаря этому пользователь получает абстрактный объект - сеть, которой может пользоваться, но не может ее разрушить. Абстрактность сети проявляется в том, что пользователь не знает деталей ее представления и реализации доступа. Принцип защиты абстракций обслуживают и другие конструкты Ады (в частности, приватные типы).

Обратите внимание, что, создав пакет управление_сетью, мы в сущности спроектировали ПОЯ, построив подходящую модель предметной области (модель сети связи). Тем самым показали, как пользоваться Адой в качестве базового ЯП. При этом средством абстрактного определения ПОЯ служит спецификация пакета, средством конкретизации - тело пакета, а средством защиты - невидимость из использующих сегментов имен, объявленных в теле пакета.

3. Важнейшие абстракции: данные, операции, связывание

3.1. Принцип единства и относительности трех абстракций

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

Однако программировать было бы невозможно, если бы не удалось разорвать единство этих ролей и рассматривать данные, в нужной степени абстрагируясь от конкретных операций; рассматривать операции, в нужной степени абстрагируясь от конкретных данных, над которыми они выполняются; и, наконец, рассматривать связывание, в нужной степени абстрагируясь от данных и операций, которых оно касается.

Полученное путем такой абстракции понятие операции отражает активное начало в поведении исполнителя, понятие данного - пассивное начало, а понятие связывания - управляющее (организующее) начало - отражает всевозможные виды управления.

Первые две роли выделяют и обсуждают чаще. Однако значение связывания никак не меньше. Как будет показано, оно отражает не только разнообразные способы управления, но и разнообразные способы конкретизации в программировании.

Важно понимать, что указанные три роли полностью различны лишь в рамках конкретного акта исполнителя. Когда же речь идет о каком-либо отдельно взятом объекте, то в зависимости от ситуации или точки зрения он вполне может выступать в различных ролях (иногда - в любой из этих ролей). В этом смысле указанные роли
(как и любые другие) относительны. Например, знак "+" чаще всего воспринимается как обозначение операции сложения. Вместе с тем он выступает в роли данного, когда фигурирует как элемент формулы, которую переводят в польскую инверсную запись. Но этот же знак связывает два операнда формулы, между которыми он помещен, предвосхищая их совместное участие в одном акте исполнителя. Этот акт будет выполнен при условии, что управление достигло именно рассматриваемого знака "+".

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24