Существенное: категории классов
Как объяснялось в главе 3, класс - необходимое, но недостаточное средство декомпозиции. Когда система разрастается до дюжины классов, можно заметить группы классов, связанные внутри, и слабо зацепляющиеся с другими. Мы называем такие группы категориями классов.
Многие объектно-ориентированные языки не поддерживают это понятие. Следовательно, выделение обозначений для категорий классов позволяет выразить важные архитектурные элементы, которые не могли быть непосредственно записаны на языке реализации [Среда программирования Smalltalk поддерживает концепцию категорий классов. Собственно это и подвигло нас на включение категорий в систему обозначений. Однако, в Smalltalk категории классов не имеют семантического содержания: они существуют только для более удобной организации библиотеки классов. В C++ категории классов связаны с концепцией компонент (Страуструп), они еще не являются чертой языка, хотя включение в него семантики пространства имен рассматривается [8]. (В настоящее время пространства имен включены в стандарт. - Примеч. ред.)].
Рис. 5-6. Значок категории классов.
Классы и категории классов могут сосуществовать на одной диаграмме. Верхние уровни логической архитектуры больших систем обычно описываются несколькими диаграммами, содержащими только категории классов.
Категории классов. Категории классов служат для разбиения логической модели системы. Категория классов - это агрегат, состоящий из классов и других категорий классов, в том же смысле, в котором класс - агрегат, состоящий из операций и других классов. Каждый класс системы должен "жить" в единственной категории или находиться на самом верхнем уровне системы. В отличие от класса, категория классов не имеет операций или состояний в явном виде, они содержатся в ней неявно в описаниях агрегированных классов.
На рис. 5-6 показан значок, обозначающий категорию классов. Как и для класса, для категории требуется имя, которое должно быть уникально в данной модели и отлично от имен классов.
Иногда полезно на значке категории перечислить некоторые из содержащихся в ней классов. "Некоторые", потому, что зачастую категории содержат довольно много классов, и перечислять их все было бы хлопотно, да это и не нужно. Так же, как список атрибутов и операций на значке класса, список классов в значке категории представляет сокращенный вид ее спецификации. Если мы хотим видеть на значке категории больше классов, мы можем его увеличить. Можно удалить разделяющую черту и оставить в значке только имя категории.
Категория классов представляет собой инкапсулированное пространство имен. По аналогии с квалификацией имен в C++, имя категории можно использовать для однозначной квалификации имен содержащихся в ней классов и категорий. Например, если дан класс A из категории B, то его полным именем будет A::B. Таким образом, как будет обсуждаться далее, для вложенных категорий квалификация имен простирается на произвольную глубину.
Некоторые классы в категории могут быть открытыми, то есть экспортироваться для использования за пределы категории. Остальные классы могут быть частью реализации, то есть не использоваться никакими классами, внешними к этой категории. Для анализа и проектирования архитектуры это различие очень важно, так как позволяет разделить обязанности между экспортируемыми классами, которые берут на себя общение с клиентами, и внутренними классами в категории, которые, собственно, выполняют работу. На самом деле, во время анализа закрытые аспекты категории классов можно опустить. По умолчанию все классы в категории определяются как открытые, если явно не указано противное. Ограничение доступа будет обсуждаться ниже.
Категория может использовать невложенные категории и классы. С другой стороны, и классы могут использовать категории. Для единообразия мы обозначаем эти экспортно-импортные отношения так же, как отношение использования между классами (см. рис. 5-4). Например, если категория A использует категорию B, это означает, что классы из A могут быть наследниками, или содержать экземпляры, использовать или быть еще как-то ассоциированы с классами из B.
Рис. 5-7. Диаграмма классов верхнего уровня для гидропонной системы.
Когда в категории слишком много общих классов, вроде базовых классов-контейнеров или других базовых классов, подобных Object в Smalltalk, возникают практические затруднения. Такие классы будут использоваться чуть ли не всеми другими категориями, загромождая корневой уровень диаграммы. Чтобы выйти из положения, такие категории помечаются ключевым словом global в левом нижнем углу значка, показывающим, что категория по умолчанию может быть использована всеми остальными.
Диаграммы классов верхнего уровня, содержащие только категории классов, представляют архитектуру системы в самом общем виде. Такие диаграммы чрезвычайно полезны для визуализации слоев и разделов системы. Слой обозначает набор категорий классов одного уровня абстракции. Таким образом, слои представляют набор категорий классов, так же как категории классов - это кластеры классов. Слои обычно нужны, чтобы изолировать верхние уровни абстракции от нижних. Разделы обозначают связанные (каким-либо образом) категории классов на разных уровнях абстракции. В этом смысле слои представляют собой горизонтальные срезы системы, а разделы - вертикальные.
Пример. На рис. 5-7 приведен пример диаграммы классов верхнего уровня для тепличного хозяйства. Это типичная многослойная система. Здесь абстракции, которые ближе к реальности (а именно активаторы и датчики климата и удобрений), располагаются на самых нижних уровнях, а абстракции, отражающие понятия пользователя, - ближе к вершине. Категория классов ТипыПосевов - глобальна, то есть ее услуги доступны всем другим категориям. На значке категории классов Планирование показаны два ее важных класса: GardeningPlan (план выращивания) с рис. 5-5 и PlanAnalyst (анализатор планов). При увеличении любой из восьми категорий классов, показанных на рисунке, обнаружатся составляющие их классы.
Рис. 5-8. Значок параметризованного класса.