На этом шаге рассмотрим экспорт и импорт элементов пакета в UML.
Предположим, в вашей модели есть два класса одного уровня, расположенных рядом друг с другом: А и В. Класс А "видит" В и наоборот, то есть любой из них может зависеть от другого. Оба они образуют тривиальную систему, и для них не надо создавать никаких пакетов. Допустим теперь, что у вас имеется несколько сотен равноправных классов. Размер сети связей, которую вы можете "соткать" между ними, не поддается воображению. Более того, столь огромную группу неорганизованных классов просто невозможно воспринять в ее целостности. Это реальная проблема больших систем: простой неограниченный доступ не позволяет осуществить масштабирование. В таких случаях для организации абстракций приходится применять пакеты.
Итак, допустим, что класс А расположен в одном пакете, а класс В – в другом, причем оба пакета равноправны. Допустим также, что А и В объявлены открытыми частями в своих пакетах. Эта ситуация коренным образом отличается от двух предыдущих. Хотя оба класса объявлены открытыми, свободный доступ одного из них к другому невозможен, ибо границы пакетов непрозрачны. Однако если пакет, содержащий класс А, импортирует пакет-владелец класса В, то А сможет "видеть" В, хотя В по-прежнему не будет "видеть" А.
Импорт дает элементам одного пакета односторонний доступ к элементам другого. На языке UML связь импорта моделируют как зависимость, дополненную стереотипом import. Упаковывая абстракции в семантически осмысленные блоки и контролируя доступ к ним с помощью импорта, вы можете управлять сложностью систем, насчитывающих множество абстракций.
Фактически в рассмотренной ситуации применяются два стереотипа – import и access, и оба они показывают, что исходный пакет имеет доступ к элементам целевого. Стереотип import добавляет содержимое целевого пакета в открытое пространство имен исходного, поэтому нет необходимости в квалификации их имен. Таким образом, возникает вероятность конфликта имен, которого необходимо избегать, если вы хотите, чтобы модель была хорошо согласована. Стереотип access добавляет содержимое целевого пакета в закрытое пространство имен исходного. Единственное различие заключается в том, что нельзя повторно экспортировать импортированные элементы, если какой-либо третий пакет импортирует первоначальный исходный пакет. Чаще используют стереотип import.
Открытые элементы пакета называют экспортируемыми. Так, на рис. 1 пакет GUI экспортирует два класса – Window (Окно) и Form (Форма).
Рис.1. Импорт и экспорт
Класс EventHandler (ОбработчикСобытий) является защищенной частью пакета. Довольно часто экспортируемыми элементами пакета являются интерфейсы.
Экспортируемые элементы будут видимы для содержимого тех пакетов, для которых видим данный пакет. В примере на рис. 1 пакет Policies (Политики) явно импортирует пакет GUI. Таким образом, классы GUI::Window и GUI::Form будут видимы для содержимого пакета Policies как классы с простыми именами Window и Form.
Но класс GUI::EventHandler будет скрыт, так как является защищенным. С другой стороны, пакет Server не импортирует GUI, поэтому элементы Server имеют доступ к открытым элементам GUI, но для этого им понадобятся квалифицированные имена, например GUI::Window. Аналогично у GUI нет доступа к содержимому пакета Server даже с использованием квалифицированных имен, поскольку оно закрыто.
Зависимости импорта и доступа являются транзитивными. В данном примере пакет Client импортирует Policies, а Policies – GUI, так что можно сказать, что Client транзитивно импортирует GUI. Если Policies имеет доступ в GUI, не импортируя его, то Client не добавляет элементы GUI к своему пространству имен, но может обращаться к ним, используя квалифицированные имена (такие как, например, GUI::Window).
Элемент, видимый внутри пакета, будет видим также и внутри всех вложенных в него пакетов. Вообще, вложенные пакеты могут "видеть" все, что "видят" включающие их пакеты. Имя во вложенном пакете может скрывать имя во включающем пакете; в этом случае для ссылки требуется квалифицированное имя.
На следующем шаге рассмотрим типичные приемы моделирования групп элементов в UML.