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

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

    Моделирование простых зависимостей

    Часто встречающийся вид зависимости – это связь класса, который использует другой класс в качестве параметра своей операции. Чтобы смоделировать эту связь использования, необходимо создать зависимость, направленную от класса с операцией к классу, используемому в качестве ее параметра. В примере на рис. 1 показан набор классов, составляющих систему, которая управляет назначением студентов и преподавателей на курсы в университете. Этот рисунок изображает зависимость от CourseSchedule (РасписаниеКурсов) к Course (Курс), поскольку Course используется в операциях add (добавить) и remove (удалить) класса CourseSchedule.


Рис.1. Связи зависимости в UML

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

    Кроме того, рис. 1 демонстрирует зависимость, которая не связана с классами в операциях, а моделирует одну общую идиому C++. Зависимость от Iterator (Итератор) говорит о том, что Iterator использует CourseSchedule, то есть CourseSchedule ничего не знает об Iterator. Зависимость помечена стереотипом <permit> (<разрешить>), который подобен предложению friend (друг) в C++.

    Моделирование одиночного наследования

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

    Чтобы смоделировать связи наследования, необходимо:

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

    На рис. 2 представлен ряд классов, формирующих приложение управления торговлей. Вы найдете здесь связь обобщения, проведенную от четырех классов – CashAccount (РасчетныйСчет), Stock (Акция), Bond (Облигация) и Property (Собственность), – к более общему классу Security (ЦенныеБумаги). Класс Security является родителем, а CashAccount, Stock, Bond и Property – потомками (дочерними классами). Каждый из этих четырех специализированных классов представляет собой некоторую разновидность Security. Последний включает две операции: presentValue (текущаяСтоимость) и history (История). Поскольку Security является родителем CashAccount, Stock, Bond и Property, все они наследуют эти две операции, равно как и любые другие атрибуты и операции Security, которые могут быть не указаны на этом рисунке.


Рис.2. Связи наследования в UML

    Имена Security и presentValue написаны курсивом не случайно. Когда вы строите иерархии, подобные той, что представлена на рис. 2, то часто сталкиваетесь с нелистовыми классами, которые неполны или для которых не может существовать объектов. Такие классы называются абстрактными. В UML вы можете пометить класс как абстрактный, написав его имя курсивом. То же касается и операций: в рассматриваемом примере операция presentValue имеет сигнатуру, но не реализуется в классе Security и должна быть реализована в виде методов на более низком уровне абстракции, поэтому ее имя также выделено курсивом. Зато все четыре непосредственных потомка Security являются конкретными (то есть не абстрактными), а значит, каждый из них обязан представить конкретную реализацию операции presentValue.

    Иерархии обобщения/специализации не обязательно ограничиваются двумя уровнями. Обычно этих уровней больше, и рис. 2. служит тому подтверждением. SmallCapStock (АкцияСМалымКапиталом) и LargeCapStock (АкцияСБольшимКапиталом) – потомки класса Stock, который, в свою очередь, является дочерним по отношению к Security. Таким образом, Security – корневой класс, поскольку он не имеет родителей. SmallCapStock и LargeCapStock – листовые классы, потому что не имеют потомков. Stock имеет как родителя, так и потомков; он не подходит под определение ни корневого, ни листового класса.

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

    Конечно, в системе наследования не может быть циклов: ни один класс не может быть своим собственным предком.

    Моделирование структурных связей

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

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

    В то время как зависимость – связь использования, а обобщение – связь наследования, ассоциация определяет структурный путь взаимодействия объектов двух классов.

    Чтобы смоделировать структурные связи, воспользуйтесь следующими рекомендациями:

  1. Установите ассоциацию между каждой парой классов, по объектам которых следует обеспечить навигацию. Это основанное на данных представление ассоциации.
  2. Установите ассоциацию между каждой парой классов, объекты одного из которых нуждаются во взаимодействии с объектами другого (но не в виде локальных переменных в процедуре или параметров операции). Это в основном поведенческое представление ассоциации.
  3. Для каждой из установленных ассоциаций специфицируйте множественность, особенно когда она не выражается символом * (звездочка), принятым по умолчанию, а также имена ролей, особенно если они помогают объяснить модель.
  4. Если класс на одном конце ассоциации структурно или организационно представляет целое, в то время как класс, находящийся на другом конце, является частью этого целого, пометьте такую связь как агрегацию (то есть добавьте к связывающей их линии ромбик со стороны целого).

    Как вы можете узнать, когда объекты одного класса должны взаимодействовать с объектами другого? Ответ – когда CRC-карточки и анализ на основе вариантов использования заставляют вас рассмотреть структурные и поведенческие сценарии. Если вы обнаруживали, что какиеFлибо классы взаимодействуют, используя связи по данным, установите между ними ассоциацию.

    Рис. 3 показывает набор классов информационной системы учебного заведения. Перечислим эти классы начиная с нижнего левого угла диаграммы: Student (Студент), Course (Курс) и Instructor (Преподаватель). Существует ассоциация между Student и Course, свидетельствующая о том, что студенты посещают курсы. Более того, каждый студент может посещать многие курсы и каждый курс может быть прочитан для многих студентов. Также вы обнаружите ассоциацию между Course и Instructor, которая говорит о том, что преподаватели ведут курсы. Для каждого курса назначен как минимум один преподаватель, причем каждый преподаватель может вести один или несколько курсов либо не вести ни одного. Каждый курс относится исключительно к одному факультету.


Рис.3. Структурные связи в UML

    Связи между классом School (Учебное заведение) и классами Student и Department (Факультет) немного иные. Здесь вы видите примеры агрегаций. Вуз может набрать или не набрать студентов; каждый студент может быть зарегистрирован в одном или нескольких вузах; в вузе имеется один или несколько факультетов, причем каждый относится исключительно к одному учебному заведению. Вы можете опустить дополнительные символы агрегации и применять простые ассоциации, но, специфицируя School как целое, а Student и Department – как его части, вы тем самым проясняете, что по отношению к чему является главным. По рисунку видно, что учебные заведения в каком-то смысле определяются его студентами и факультетами. Впрочем, студенты и факультеты тоже не существуют сами по себе, вне вуза, к которому они прикреплены. Они получают свой статус только в связи с учебным заведением (так, человек, не учащийся в вузе, лишается права именоваться студентом).

    Кроме того, существуют две ассоциации между Department и Instructor. Одна из них показывает, что каждый преподаватель работает на одном или нескольких факультетах и каждому факультету сопоставлен один или несколько преподавателей. Эта связь моделируется как агрегация, поскольку организационно факультеты в структуре учебного заведения находятся выше, чем преподаватели. Вторая ассоциация, установленная для каждого факультета, говорит о том, что на факультете есть один начальник – преподаватель, занимающий должность декана. Из приведенной модели явствует, что преподаватель может быть деканом не более чем на одном факультете, а некоторые преподаватели не являются деканами ни одного факультета.

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

    Моделируя связи на UML, соблюдайте следующие правила:

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

    На следующем шаге рассмотрим понятие классификации.




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