Язык UML. Руководство пользователя

       

Ассоциации


Ассоциацией (Association) называется структурное отношение, показывающее, что объекты одного типа неким образом связаны с объектами другого типа. Если между двумя классами определена ассоциация, то можно перемещаться от объектов одного класса к объектам другого. Вполне допустимы случаи, когда оба конца ассоциации относятся к одному и тому же классу. Это означает, что с объектом некоторого класса позволительно связать другие объекты из того же класса. Ассоциация, связывающая два класса, называется бинарной. Можно, хотя это редко бывает необходимым, создавать ассоциации, связывающие сразу несколько классов; они называются n-арными. Графически ассоциация изображается в виде линии, соединяющей класс сам с собой или с другими классами. Используйте ассоциации, когда хотите показать структурные отношения. (Ассоциации и зависимости, в отличие от отношений обобщения, могут быть рефлексивными - см. главу 10.)

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

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


Рис. 5.4 Имена ассоциаций

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

Роль. Класс, участвующий в ассоциации, играет в ней некоторую роль. По существу, это "лицо", которым класс, находящийся на одной стороне ассоциации, обращен к классу с другой ее стороны. Вы можете явно обозначить роль, которую класс играет в ассоциации. На рис. 5.5 показано, что класс Человек, играющий роль работника, ассоциирован с классом Компания, играющим роль работодателя.
Роли тесно связаны с семантикой интерфейсов (см. главу 10).


Рис. 5.5 Роли

Примечание: Один класс может играть в разных ассоциациях как одну и ту же роль, так и различные.

Кратность. Ассоциации отражают структурные отношения между объектами. Часто при моделировании бывает важно указать, сколько объектов может быть связано посредством одного экземпляра ассоциации (то есть одной связи, см. главу 15). Это число называется кратностью (Multiplicity) роли ассоциации и записывается либо как выражение, значением которого является диапазон значений, либо в явном виде, как показано на рис. 5.6. Указывая кратность на одном конце ассоциации, вы тем самым говорите, что на этом конце именно столько объектов должно соответствовать каждому объекту на противоположном конце. Кратность можно задать равной единице (1), можно указать диапазон: "ноль или единица" (0..1), "много" (0..*), "единица или больше" (1..*). Разрешается также указывать определенное число (например, 3).


Рис. 5.6 Кратность

Примечание: С помощью списка можно задать и более сложные кратности, например 0 . . 1, 3..4, 6..*, что означает "любое число объектов, кроме 2 и 5".



Агрегирование. Простая ассоциация между двумя классами отражает структурное отношение между равноправными сущностями, когда оба класса находятся на одном концептуальном уровне и ни один не является более важным, чем другой. Но иногда приходится моделировать отношение типа "часть/целое", в котором один из классов имеет более высокий ранг (целое) и состоит из нескольких меньших по рангу (частей). Отношение такого типа называют агрегированием; оно причислено к отношениям типа "имеет" (с учетом того, что объект-целое имеет несколько объектов-частей). Агрегирование является частным случаем ассоциации и изображается в виде простой ассоциации с незакрашенным ромбом со стороны "целого", как показано на рис. 5.7. Существует много важных разновидностей этого отношения (см. главу 10).


Рис. 5.7 Агрегирование

Примечание: Незакрашенный ромб отличает "целое" от "части"- - и только. Эта простая форма агрегирования является чисто концептуальной; она не влияет на результат навигации по ассоциации между целым и его частями и не подразумевает наличия между ними какой-либо зависимости по времени жизни.



Как видно из рис. 10.5, для этого нужно смоделировать ассоциацию между классами РабочийСтол и Возвращен-ноеИзделие. Применительно к РабочемуСтолу определен jobID - идентификатор задания, связанный с каждым конкретным ВозвращеннымИзделием. В этом смысле jobID - атрибут ассоциации (см. главы 4 и 9). Он не является свойством объекта ВозвращенноеИзделие, поскольку изделия ничего не знают ни о ремонте, ни о заданиях. Если известен объект РабочийСтол и значение jobID, то можно осуществить навигацию к нулю или одному объекту ВозвращенноеИзделие. В языке UML эта идиома моделируется с помощью квалификатора, являющегося атрибутом ассоциации, значения которого разбивают множество объектов на подмножества, связанные с объектом на другом конце ассоциации. Квалифика-тор изображается в виде маленького прямоугольника, присоединенного к одной из концевых точек ассоциации, внутри которого располагаются атрибуты квалификатора (см. рис. 10.5). Объект-источник вместе со значениями атрибутов квалификатора порождает один целевой объект (если кратность цели не больше единицы) или множество таких объектов (если кратность больше единицы).


Рис. 10.5 Квалификатор

Примечание: Семантика квалификаторов нетривиальна, и существует ряд сложных примеров их использования. Однако чаще всего ситуации, в которых нужны квалификаторы, довольно просты. Если на одном конце ассоциации вы можете поместить поисковую структуру данных (например, хэш-таблииу или В-дерево), то объявите индекс, по которому производится поиск, как Квалификатор. Обычно кратность на исходном конце будет "много", а на целевом - 0..1.

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


Так, в словаре системы управления человеческими ресурсами класс Person (Сотрудник) способен реализовывать несколько интерфейсов: IManager (Управляющий), lEmployee (Работник), IOfficer (Служащий) и т.д. Как видно из рис. 10.6, отношения между начальником и подчиненными можно моделировать с помощью ассоциации типа "один ко многим", явно пометив роли в ней (см. главу 4) как supervisor (контролер) и worker (рабочий). В контексте этой ассоциации объект класса Person в роли supervisor предоставляет объектам worker только интерфейс Imanager; он же в роли worker предоставляет объекту supervisor лишь интерфейс IEmployee. На рисунке показано, что можно явно описать тип роли с помощью синтаксиса rolename : iname, где iname - некоторый интерфейс другого классификатора (см. главу 9).


Рис. 10.6 Указание типов интерфейсов

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

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

Это означает, что в случае композитного агрегирования объект в любой момент времени может быть частью только одного композита. Например, в оконной системе класс Frame (Рама) принадлежит только одному классу Window (Окно), тогда как при простом агрегировании "часть" может принадлежать одновременно нескольким "целым".


Скажем, в модели дома объект Стена может принадлежать нескольким объектам Комната.

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

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


Рис. 10.7 Композиция

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

Классы-ассоциации. В ассоциации между двумя классами сама ассоциация также может иметь свойства. Например, в отношениях типа "работодатель/работник" между классами Компания и Человек имеется объект Работа, который описывает свойства отношения, применимые только к одной паре объектов Компания и Человек. Моделирование данной ситуации с помощью пары ассоциаций от Компании к Работе и от Работы к Человеку было бы неправильно, поскольку таким образом нельзя передать связь конкретного экземпляра объекта Работа с конкретной парой классов Компания и Человек.

На языке UML такая ситуация моделируется с помощью класса-ассоциации (Association class) - элемента, сочетающего в себе свойства как ассоциации, так и класса. Это означает, что класс-ассоциацию можно считать или ассоциацией, имеющей свойства класса, или классом со свойствами ассоциации. Изображают его в виде класса, соединенного пунктирной линией с ассоциацией, как показано на рис. 10.8.


Рис. 10.8 Классы-ассоциации

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


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

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

Прежде всего, можно указать, является ассоциация реальной или концептуальной:

  • Q implicit (неявный) - говорит о том, что данное отношение не показано явно (сделать вывод о его наличии можно только логическим путем), то есть является исключительно концептуальным. Например, если имеется ассоциация между двумя базовыми классами, то вы можете определить ту же самую ассоциацию и между их потомками (так как они наследуют отношения родительских классов). При этом данное отношение будет помечено словом implicit, поскольку оно не задано отдельно, а неявно вытекает из отношения, которое существует между родительскими классами.

    Во-вторых, можно указать, упорядочены ли объекты на одном конце ассоциации (если ее кратность больше единицы):

  • ordered (упорядоченный) - определяет, что объекты на одном конце ассоциации явным образом упорядочены. Например, в ассоциации User/Password связанные с пользователем (User) пароли (Password) могут храниться в порядке их использования; в этом случае они должны быть помечены ключевым словом ordered.

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

  • changeable (изменяемый) - показывает, что можно добавлять, удалять и изменять связи между объектами;
  • addOnly (только добавляемый) - говорит, что от объекта на противоположном конце ассоциации можно добавлять новые связи (см.главу 15);
  • frozen (замороженный) - означает, что связь, добавленная от объекта на противоположном конце ассоциации, не может быть впоследствии изменена или удалена.

    Примечание: Строго говоря, ordered, changeable, frozen и addOnly - это свойства концевой точки ассоциации. Однако изображаются они с помощью нотации ограничений.


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