С одной стороны, после этого шага мы можем быть довольны - внешние требования к проектируемому комплексу услуг в первом приближении выполнены. С другой стороны, появилась необходимость определить упомянутые на предыдущих шагах типы данных.
Так всегда - завершая абстракцию и конкретизацию верхнего уровня, создаем почву для аналогичной работы на нижнем уровне и наоборот.
Шаг 2.4 (строка 2). Определяем тип "узел". Этот тип уже частично нами охарактеризован (где?) - данные типа "узел" могут служить аргументами всех процедур и функций, объявленных в нашем пакете. Другими словами, рассматриваемый тип уже охарактеризован по фактору применимых операций. Выписывая его явное определение, мы характеризуем данные этого типа по фактору изменчивости - указываем, что диапазон (range) их возможных значений - целые числа от 1 до числа макс_узлов (пока еще не определенного). Одновременно мы относим объявляемый тип к категории целых числовых типов и тем самым завершаем его характеристику по фактору применимых операций (в Аде для целых типов предопределены обычные операции целой арифметики - сложение "+", вычитание "-", умножение "*" и др.).
Шаг 2.5 (строки 6-10). Определяем тип "связи" результата функции все_связи. Замысел в том, чтобы эта функция сообщала число связей указанного узла и перечень связанных с ним узлов. В Алголе-60 или Фортране не могло быть функций, которые в качестве результата выдают составной объект. В Аде можно ввести составной тип, объекты которого состоят либо из однотипных подобъектов - являются массивами, либо из разнотипных - являются записями. Результат задуманной нами функции все_связи - пара разнотипных объектов (число и узлы). Другими словами, это запись, первое поле которой называется "число", а второе - "узлы". Тип значений первого поля назван "число_связей", второго - "перечень_связей".
В этом же объявлении указано, что при создании объекта типа "связи" его поле "число" получает начальное значение 0. Это так называемая ИНИЦИАЛИЗАЦИЯ объектов, которой нет, например, в Алголе-60, но для знающих Фортран - дело привычное (вспомните объявление начальных данных DATA).
Итак, на шаге 2.5 снова кое-что определилось, но опять появились новые имена - число_связей и перечень_связей.
Шаг 2.6 (строка 5). Перечень_связей определяем как регулярный тип одномерных массивов, составленных из объектов типа узел, доступ к которым - по индексам типа индекс_узла.
Шаг 2.7 (строка 4). Индекс_узла определяем как тип объектов, значения которых лежат в диапазоне целых чисел от 1 до макс_связей (максимального числа связей у узла в сети - оно пока не определено).
Шаг 2.8 (строка 3). Число_связей определяем как тип объектов, значения которых лежат в диапазоне целых чисел от 0 до макс_связей. Как видите, этот тип похож на предыдущий, но отличается своей ролью и диапазоном значений.
Остались неопределенными только имена макс_узлов и макс_связей. Их неудобно фиксировать в том же модуле - ведь они могут изменяться в зависимости от потребностей пользователя и наличных ресурсов. Поэтому будем считать, что эти имена определены во внешнем для нашего модуля контексте, а именно в пакете с именем "параметры_сети". Доступ к этому контексту из модуля управление_сетью обеспечивается его нулевой строкой.
Это так называемое УКАЗАНИЕ КОНТЕКСТА. После ключевого слова with в нем перечисляются пакеты, объявления из которых считаются видимыми в модуле, непосредственно следующем за таким указанием.
Пакет параметры_сети можно определить, например, так:
1. package параметры_сети is
2. макс_узлов : constant INTEGER := 100;
3. макс_связей: constant INTEGER := 8;
4. end параметры_сети;
Тем самым макс_узлов определено в качестве ПОСТОЯННОЙ целого типа со значением 100, а макс_связей - в качестве постоянной того же типа со значением 8. Значения постоянных нельзя менять при исполнении программы (вот еще один элемент прогнозирования и контроля в Аде).
2.5. Замечания о конструктах
Рассмотрим написанные фрагменты программы еще раз. Теперь поговорим о строении, смысле и назначении использованных конструктов.
В целом мы написали две СПЕЦИФИКАЦИИ ПАКЕТА. Отличительный признак этого конструкта - ключевое слово package (пакет). Спецификация пакета содержит объявления имен, которые становятся доступными при использовании пакета посредством указания контекста (например, объявления из пакета параметры_сети становятся доступны в пакете управление_сетью, если указать контекст with параметры_сети).
Спецификацию пакета можно оттранслировать и поместить в ТРАНСЛЯЦИОННУЮ БИБЛИОТЕКУ. Получится модуль, пригодный для связывания (посредством указаний контекста) с другими (использующими его) модулями в процессе их трансляции и загрузки.
Пакет может состоять из одной спецификации или из спецификации и тела. Например, для пакета параметры_сети тело не требуется в отличие от пакета управление_сетью (как Вы думаете, почему?).
Если пакет состоит из двух частей (спецификации и тела), то выполнять программу, в которой отсутствует одна из них, нельзя. Однако для трансляции использующих модулей достаточно одной только спецификации используемого пакета. Итак, создавать и транслировать спецификации пакетов можно отдельно от их тел, но исполнять - только совместно с телами пакетов. В спецификацию пакета входит совокупность ОБЪЯВЛЕНИЙ.
Так, в каждой из строк 2-3 спецификации пакета параметры_сети находится ОБЪЯВЛЕНИЕ ПОСТОЯННОЙ, точнее, ОБЪЯВЛЕНИЕ ЧИСЛА. Это одна из разновидностей ОБЪЯВЛЕНИЯ ОБЪЕКТА. Назначение всякого объявления объекта - связать имя с характеристиками поведения объекта, названного этим именем. Поэтому обязательными компонентами объявления служат само вводимое имя, ключевые слова, отличающие разновидность объявления и тем самым характеризующие поведение объявляемого объекта в целом, и компоненты-параметры, уточняющие характеристики поведения.
Так, в строке 2 объявляемое имя - макс_узлов, уточняющие параметры - имя типа (INTEGER) и константа 100 (изображение целого числа). Полное объявление связывает с именем объекта макс_узлов тип INTEGER и константу 100 как характеристику поведения объекта. Попросту говоря, имя макс_узлов начинает обозначать константу 100 типа INTEGER.
Чтобы понять, зачем нужно обозначать константы именами, достаточно представить себе программу, где константа 100 используется в десяти местах, и допустить, что нужно изменить ее значение на 200. Тогда в нашей спецификации достаточно изменить одну цифру в строке 2, а иначе пришлось бы изменять десять мест с риском где-нибудь заменить не ту константу (или не на то значение). Так объявления постоянных способствуют надежности Ада-программ.
Вернёмся к спецификации пакета управление_сетью (на стр. 30). В каждой из ее строк 2,3 и 4 мы написали ОБЪЯВЛЕНИЕ ТИПА. В нем всегда указывают, как совокупность значений объявляемого типа образуется из совокупности значений ранее известных типов (предопределенных или ранее объявленных). В нашем случае в строке 2 указано, что новый тип "узел" образован из предопределенного типа INTEGER (является типом, ПРОИЗВОДНЫМ от типа INTEGER), причем данные типа "узел" могут обозначать только целые из диапазона от 1 до макс_узлов. В строке 3 и 4 аналогичные сведения сообщаются о типах число_связей и индекс_узла, только здесь указаны другие диапазоны.
Напомним, зачем нужны объявления типов. В том модуле, где будет использоваться пакет управление_сетью, можно объявить переменную (например, А) типа "узел" и переменную (например, В) типа число_связей. Так вот переменную А можно указать в качестве аргумента процедуры "вставить" или "связать", а переменную В - нельзя. Это ошибка, обнаруживаемая при трансляции, В сущности, ради такого контроля и нужны объявления типов, прогнозирующие поведение (возможные роли) соответствующих данных.
В строке 5 - объявление типа, но на этот раз не скалярного (как в строках 2-4), а СОСТАВНОГО, точнее РЕГУЛЯРНОГО. Указано, как значения нового типа перечень_связей образуются из значений типов "узел" и индекс_узла. Именно, значения типа перечень_связей - это одномерные (так как указан лишь один диапазон индексов) МАССИВЫ, компонентами которых служат значения типа узел, а доступ к этим компонентам - по индексам типа индекс_узла.
В строках 6-10 - также объявление составного типа, но на этот раз - КОМБИНИРОВАННОГО. Указано, что значениями нового типа "связи" могут быть любые ЗАПИСИ с двумя полями. Первое поле с именем "число" и допустимыми значениями типа "число_связей" (при создании записи этому полю присваивается начальное значение 0). Второе поле с именем "узлы" типа перечень_связей.
Если в модуле, использующем наш пакет, объявлена переменная, например, X типа "связи" и I типа индекс_узла, то через Х. узлы(I) обозначается значение типа узел, которое служит I-й компонентой поля "узлы" переменной X.
Строки 11 и 15 - это примечания, не влияющие на смысл модуля. Примечанием считается остаток любой строки, начинающийся с двух минусов.
Иногда мы будем переносить примечания на следующие строчки, не предваряя продолжение примечаний двумя дефисами. Стандарт Ады такого не допускает.
В строках 12-14 - ОБЪЯВЛЕНИЯ ПРОЦЕДУР. В скобках указаны имена (названия) формальных параметров, их типы и РЕЖИМ использования (in - только для чтения - ВХОДНЫЕ параметры; out - только для записи - ВЫХОДНЫЕ; in out - и для чтения, и для записи - ОБНОВЛЯЕМЫЕ). Режим in напоминает вызов параметров значением в Алголе или Паскале, in out - вызов параметров со спецификацией var в Паскале или ссылкой в Фортране, out - точного аналога в этих ЯП не имеет.
В строках 16-17 - ОБЪЯВЛЕНИЯ ФУНКЦИЙ. Отличаются от процедур ключевым словом function (а не procedure) и указанием типа результата (после return). Режим параметров не указывается, потому что для функций всегда подразумевается режим in (все параметры функций - только входные, т. е. функции не могут менять значения своих аргументов).
|
Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |


