Шаг 52.
Унифицированный язык моделирования UML.
Базовые понятия связей в UML

    На этом шаге рассмотрим базовые понятия связей в UML.

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

    В объектно-ориентированном моделировании существуют три вида связей между классами, которые наиболее важны: зависимость, представляющая связи использования между классами (включая уточнение, трассировку и связывание); обобщение, которое связывает обобщенные классы с их специализациями; ассоциации, описывающие структурные связи объектов. Каждая из этих разновидностей представляет отдельный способ комбинирования абстракций.

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

    Вернемся к метафоре строительства дома. Стены, двери, окна, встроенные шкафы и системы освещения формируют часть вашего словаря. Однако ни одна их этих вещей не существует в отдельности: одна стена соединяется с другими, двери и окна вмонтированы в стены, открывая в них проемы, встроенные шкафы и системы освещения крепятся к стенам и потолкам. И все эти объекты – стены, двери, окна, шкафы и осветительные приборы – в совокупности формируют более высокоуровневые сущности (комнаты).

    Тем не менее вы обнаружите между этими сущностями не только структурные, но и иные связи. Например, ваш дом имеет окна, но они могут быть неодинаковы. У вас может быть большое окно в гостиной, которое не открывается, и маленькое кухонное, которое открывается. Некоторые окна открываются вверх или вниз; другие (скажем, патио) сдвигаются влево или вправо. Далее, рама бывает одинарной или двойной и т.д. Но независимо от этих различий, в каждом окне присутствует некоторый признак «оконности»: все они открывают проем в стене и предназначены для того, чтобы пропускать свет, воздух.

    Связь (relationship) – это соединение сущностей. Связь изображается в виде пути с использованием разнообразных типов линий, каждый из которых соответствует определенному виду связи.

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


Рис.1. Графическое представление связей в UML

    В UML способы соединения сущностей друг с другом, логические либо физические, моделируются связями:

  1. Зависимости

        Зависимость (dependency) – это связь, которая устанавливает, что одна сущность, например класс Window (Окно), использует информацию и сервис (операцию либо услугу), представляемые другой сущностью, например классом Event (Событие), но не обязательно – наоборот. Зависимость изображается в виде пунктирной линии со стрелкой, направленной на зависимую сущность. Выбирайте зависимость, когда вам нужно показать, что одна сущность использует другую.

        Чаще всего вы будете применять зависимости для того, чтобы показать, что один класс использует операции другого класса (либо использует переменные или аргументы типа другого класса). Это очень похоже на связь использования: если используемый класс изменяется, это может затронуть операции других классов, поскольку используемый класс теперь может предоставлять другой интерфейс или поведение. UML допускает создание зависимостей и между другими элементами, в частности между примечаниями и пакетами.

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

  2. Обобщения

        Обобщение (generalization) – это связь между сущностью общего характера (называемой суперклассом, или родителем) и более специфичной сущностью (называемой подклассом, дочерним классом или потомком). Иногда обобщение называют связью типа "является": к примеру, класс Rectangle (Прямоугольник) является разновидностью более общей сущности, класса Shape (Графический элемент). Объекты дочернего класса могут быть использованы как переменные или параметры типа его родителя, но не наоборот. Другими словами, дочерняя сущность может быть подставлена там, где объявлена родительская. Дочерняя сущность наследует свойства родителя, а именно его атрибуты и операции. Часто, хотя и не всегда, потомок имеет дополнительные атрибуты и операции помимо родительских. Реализация операции в дочернем классе замещает реализацию той же операции родителя – это явление называется полиморфизмом. Одинаковые операции должны иметь одинаковую сигнатуру (имя и параметры).

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


    Рис.2. Пример обобщения в UML

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

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

        Чаще всего вы будете использовать обобщения между классами и интерфейсами, чтобы отобразить связь наследования. Кроме того, в UML можно описать обобщение между другими элементами, например узлами.

        Обобщение с именем означает декомпозицию суперкласса на подклассы в каком-то определенном аспекте, называемом набором обобщения (generalization set). Множественные наборы обобщения ортогональны; суперкласс может быть специализирован с применением множественного наследования для выбора одного подкласса из каждого набора обобщения.

  3. Ассоциации

        Ассоциация – это структурная связь, указывающая, что объекты одной сущности соединяются с объектами другой. Так, имея ассоциацию между двумя классами, вы можете соединить объекты одного класса с объектами другого. Вполне допустимо, чтобы оба конца ассоциации соединяли один и тот же класс – иными словами, один объект класса может связываться с другим объектом того же класса. Ассоциация, связывающая два класса, называется бинарной.

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

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


    Рис.3. Имена ассоциации в UML

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

        Когда класс участвует в ассоциации, он выполняет в этой связи конкретную роль. Роль – это "лицо" класса, который находится на дальнем конце ассоциации, представленное классу, находящемуся на ее ближнем конце. Вы можете явно именовать роль, которую выполняет класс в ассоциации.

        Роль, которую играет класс, находящийся на конце ассоциации, называется конечным именем (в первой версии UML она называлась именем роли). На рис. 4 класс Person (Человек), играющий роль employee (работник), ассоциирован с классом Company (Компания), играющим роль employer (работодатель).


    Рис.4. Имена ролей в UML

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

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

        Ассоциация представляет структурную связь между объектами. Во многих ситуациях моделирования важно знать, сколько объектов может быть соединено одним экземпляром ассоциации. Этот параметр называется множественностью роли ассоциации. Множественность (multiplicity) представляет диапазон целых чисел, указывающий возможное количество связанных объектов. Он записывается в виде выражения с минимальным и максимальным значением, которые могут быть равны; для их разделения используются две точки. Устанавливая множественность дальнего конца ассоциации, вы указываете, сколько объектов может существовать на дальнем конце ассоциации для каждого объекта класса, находящегося на ближнем ее конце. Количество объектов должно находиться в пределах заданного диапазона. Множественность может быть определена как единица (1), ноль или один (0..1), много (0..*), один или несколько (1..*). Вы можете задавать диапазон целых значений, например 2..5, или устанавливать точное число, например 3 (эквивалент записи 3..3).

        В примере на рис. 5 каждая компания может нанимать одного или нескольких человек (множественность 1..*); каждому человеку сопоставлено 0 или более компаний-работодателей (множественность * – эквивалент записи 0..*).


    Рис.5. Множественность роли ассоциации в UML

        Простая ассоциация между двумя классами представляет структурную связь между равноправными элементами: оба класса концептуально находятся на одном уровне – ни один из них не может считаться важнее другого. Рано или поздно вам понадобится смоделировать связь "целое-часть", в которой один класс представляет крупную сущность (целое), содержащую в себе более мелкие (части). Этот тип связей, основанных на отношениях обладания, называется агрегацией и подразумевает, что объект-целое обладает объектами-частями. По сути, агрегация – это особый вид ассоциации, поэтому изображается она линией простой ассоциации, к которой добавлен пустой ромбик со стороны объекта-целого (рис. 6).


    Рис.6. Агрегация в UML

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

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

    Зависимости, обобщения и ассоциации являются статическими сущностями, определенными на уровне классов. В UML эти связи обычно визуализируются в диаграммах классов.

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

    На следующем шаге рассмотрим типичные приемы моделирования связей в UML.




Предыдущий шаг Содержание Следующий шаг