На этом шаге рассмотрим отношения между классами как один из элементов диаграммы классов в UML.
Классы редко бывают изолированными, они взаимодействуют друг с другом, используя разные методы. К основным отношениям между классами относятся ассоциация (association), обобщение (generalization), агрегация (aggregation) и объединение (composition). Их пиктограммы представлены на рис. 1.
Рис.1. Отношения между классами
Каждое отношение сопровождается текстуальной меткой, в которой указывается имя отношения или его предназначение. Кроме того, участники ассоциации также могут иметь метки. Правда, обе метки, как правило, не используются одновременно.
Пиктограмма ассоциации соединяет два класса и означает семантическую связь между ними. Ассоциации часто обозначаются именными группами, например Анализирует, описывающими природу связи (см. рис. 1). Класс может иметь ассоциацию с самим собой (так называемая рефлексивная ассоциация (reflexive association)), например, для отражения взаимодействия между экземплярами класса PlanAnalyst. В этом случае обозначение участников ассоциации и самой ассоциации позволяет внести ясность в диаграмму. Одна пара классов может иметь несколько ассоциативных связей. Возле пиктограммы ассоциации можно указать ее кратность. Обозначение кратности пишется возле целевого полюса ассоциации (target end). Оно указывает количество связей между каждым экземпляром класса с экземплярами целевого класса. Если кратность отношения явно не указана, то следует считать, что она не определена. Лучше всегда указывать кратность отношения, чтобы не возникало недоразумений.
Обозначения оставшихся трех типов связи уточняют пиктограмму ассоциации. Это позволяет уточнять отношения на этапе разработки проекта. Сначала констатируется существование семантической связи между двумя классами, а затем, после принятия тактических решений об истинной природе этих отношений, эта связь уточняется как обобщение, агрегация или объединение.
Пиктограмма обобщения означает отношение обобщения/специализации (отношение "является") и изображается в виде закрытой стрелки. Конец стрелки указывает на суперкласс, а ее противоположный конец обозначает подкласс. Класс GrowingPlan (План выращивания) на рис. 1 является суперклассом, а класс FruitGrowingPlan (План выращивания фруктов) — его подклассом. В соответствии с правилами выбранного языка реализации, подкласс наследует структуру и функциональные свойства своего суперкласса. Класс может иметь один (одиночное наследование) или несколько (множественное наследование) суперклассов. Конфликты имен между суперклассами разрешаются в соответствии с правилами выбранного языка программирования. Кроме того, отношения обобщения не должны быть кратными.
Агрегация, будучи отношением "является частью", является частным вариантом отношения ассоциации. Пиктограмма агрегации обозначает иерархию "целое/часть" и подразумевает возможность перемещаться от объединения к его частям. Агрегация изображается в виде линии с незакрашенным ромбом на конце, указывающим на агрегат (целое). Класс на другом конце стрелки — это класс, экземпляры которого являются частями объекта агрегата. Допускаются рефлексивная и циклическая агрегации. Иерархия "целое/часть" не всегда означает физическое включение. Например, профессиональное сообщество имеет множество членов, но это не значит, что оно ими владеет. На рис. 1 показано, что класс EnvironmentalController содержит классы Light, Heater и Cooler. Кратность * (т.е. нуль или больше), указанная возле линии, изображающей отношение агрегации, подчеркивает отсутствие физического включения.
Выбор отношения агрегации обычно осуществляется на этапе анализа или архитектурного проектирования. Выбор отношения объединения (физического включения) представляет собой пример тактического решения. Отношение включения имеет большое значение, поскольку оно играет важную роль в процессе конструирования и уничтожения частей агрегата. Пиктограмма объединения изображается в виде линии с закрашенным ромбом на конце, соединенном с агрегатом. Кратность этой линии равна 1, поскольку часть агрегата не имеет смысла за его пределами. Таким образом, продолжительность существования части совпадает с продолжительностью существования целого. Класс Foodltem на рис. 1 физически содержит классы VitaminContent и CaloricEquivalent.
Рассмотрим следующий пример. На рис. 2 показан класс CropHystory (ИсторияПосевов), экземпляры которого физически содержат неограниченное количество экземпляров классов NutrientSchedule (ПитательныеВещества) и ClimateEvent (КлиматическиеУсловия).
Рис.2. Физическое включение
Объединение означает, что создание и уничтожение этих частей происходит вследствие создания или уничтожения агрегата. В противоположность этому, каждый экземпляр класса CropHystory не содержит ни одного экземпляра класса Crop (Посев). Это значит, что продолжительности существования этих двух объектов не зависят друг от друга, хотя один из них можно считать частью другого.
Описанные выше пиктограммы являются основными элементами диаграмм классов. В совокупности они позволяют разработчику достаточно полно описать структуру классов системы.
На следующем шаге рассмотрим понятие параметризованных классов.