Ада-95. Компилятор GNAT

         

Подсистемы


Большие системы обычно состоят из сотен и даже тысяч самостоятельных компонентов.

Обычно не требуется, чтобы каждый отдельный компонент активно взаимодействовал со всеми остальными частями системы.

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

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

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

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

Любой вид библиотечных модулей (подпрограммы, пакеты...) может быть описан как дочерний модуль библиотечного пакета (или настраиваемого модуля).

Это позволяет строить иерархии библиотечных модулей.

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

Подсистема (subsystem) - это иерархия библиотечных модулей.

Она может состоять из подпрограмм, но чаще всего она состоит из иерархии пакетов.

Подсистема может быть настраиваемой, в таком случае все потомки (дочерние модули) также должны быть настраиваемыми.

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

Спецификация всей подсистемы - это иерархия спецификаций ее публичных модулей.

Дочерний модуль может быть приватным модулем.

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



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




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

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

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

Разделение компонентов подсистемы на модули предков и их потомков позволяет осуществлять изменения дочерних модулей без необходимости перекомпиляции модулей предков или независимых родственных дочерних модулей.

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

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

Использование иерархических модулей предусматривает улучшенное управление пространством имен.

Предположим, что кто-то приобрел два семейства программных компонентов.

Одно, у Mr. Usable, который написал пакет Strings, для строковой обработки.

Другое, у Mr. Reusable, которое также включает пакет с именем Strings.

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

С другой стороны, если для семейств компонентов предусмотрены префиксы Usable.Strings и Reusable.Strings, то коллизии имен не происходит.

Это дает нам возможность сконцентрировать свои усилия на управлении пространством имен для подсистем или семейств компонентов вместо управления плоским пространством имен для всех компилируемых модулей.

Такое структурирование пространства имен можно обнаружить в предопределенном окружении Ады: теперь, все предопределенные пакеты являются дочерними модулями пакетов Ada, System и Interfaces



( с соответствующими библиотечными переименованиями для поддержки обратной совместимости с Ada 83).

Предположим, что существует сложная абстракция, которая инкапсулирована в единую подсистему.

Кто-либо может предусмотреть различное специализированное представление такой абстракции посредством различных интерфейсных пакетов подсистемы.

Такой подход похож на представление в базе данных.

Например, простой банковский счет может иметь balance (остаток на счете) и interest_rate (процентная ставка).

Представление заказчика заключается в том, что он может выполнить deposit (положить на счет) или withdraw (снять со счета), и посмотреть состояние interest_rate.

Представление клерка в банке заключается в том, что он может изменить interest_rate для любого банковский счета.

Очевидно, что два таких представления не должны быть объединены в единый интерфейс (банк не позволяет заказчикам изменять interest_rate).

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

Рассмотрим пример операционной системы (например POSIX).

Очевидно, что никто не желает иметь один большой пакет с сотнями типов и операций.

Должно существовать логическое группирование типов и операций.

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

Иерархические модули позволяют логическое структурировани и группирование, вне зависимости от используемых приватных описаний типов.

Подсистема может иметь маленький и простой интерфейс, и при этом быть очень сложной и иметь большую реализацию.

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

Предположим, что существуют две подсистемы.

Например, Radar и Motor.

Между разными группами разработчиков, при разработке своих подсистем, не будет возникать коллизия имен "вспомогательных пакетов".

Например, для Radar.Control и Motor.Control.

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

Содержание раздела