Моделирование на UML. Общие диаграммы

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

Диаграмма использования (use case diagram) ‒ это наиболее общее представление функционального назначения системы.

Диаграмма использования призвана ответить на главный вопрос моделирования: что делает система во внешнем мире?

На диаграмме использования применяются два типа основных сущностей: варианты использования 1 и действующие лица 2, между которыми устанавливаются следующие основные типы отношений:

  • ассоциация между действующим лицом и вариантом использования 3;
  • обобщение между действующими лицами 4;
  • обобщение между вариантами использования 5;
  • зависимости (различных типов) между вариантами использования 6.

На диаграмме использования, как и на любой другой, могут присутствовать комментарии 7. Более того, это настоятельно рекомендуется делать для улучшения читаемости диаграмм.

Основные элементы нотации, применяемые на диаграмме использования, показаны ниже. Детальное описание приведено в разделе 2.2.

Рис. Нотация диаграммы использования

Диаграмма классов (class diagram) ‒ основной способ описания структуры системы.

Это не удивительно, поскольку UML в первую очередь объектно-ориентированный язык, и классы являются основным (если не единственным) «строительным материалом».

На диаграмме классов применяется один основной тип сущностей: классы 1 (включая многочисленные частные случаи классов: интерфейсы, примитивные типы, классы-ассоциации и многие другие), между которыми устанавливаются следующие основные типы отношений:

  • ассоциация между классами 2 (с множеством дополнительных подробностей);
  • обобщение между классами 3;
  • зависимости (различных типов) между классами 4 и между классами и интерфейсами.

Некоторые элементы нотации, применяемые на диаграмме классов, показаны ниже. Детальное описание приведено в главе 3.

Рис.

Нотация диаграммы классов

Диаграмма автомата (state machine diagram) ‒ это один из способов детального описания поведения в UML на основе явного выделения состояний и описания переходов между состояниями.

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

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

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

Рис. Нотация диаграммы автомата

Диаграмма деятельности (activity diagram) ‒ способ описания поведения на основе указания потоков управления и потоков данных.

Диаграмма деятельности ‒ еще один способ описания поведения, который визуально напоминает старую добрую блок-схему алгоритма. Однако за счет модернизированных обозначений, согласованных с объектно-ориентированным подходом, а главное, за счет новой семантической составляющей (свободная интерпретация сетей Петри), диаграмма деятельности UML является мощным средством для описания поведения системы.

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

Рис. Нотация диаграммы деятельности

Диаграмма последовательности (sequence diagram) ‒ это способ описания поведения системы на основе указания последовательности передаваемых сообщений.

Фактически, диаграмма последовательности ‒ это запись протокола конкретного сеанса работы системы (или фрагмента такого протокола). В объектно-ориентированном программировании самым существенным во время выполнения является пересылка сообщений между взаимодействующими объектами. Именно последовательность посылок сообщений отображается на данной диаграмме, отсюда и название.

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

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

Ось времени может быть направлена горизонтально, в этом случае считается, что время течет слева направо.

На следующем рисунке показаны основные элементы нотации, применяемые на диаграмме последовательности. Для обозначения самих взаимодействующих объектов применяется стандартная нотация ‒ прямоугольник с именем экземпляра классификатора. Пунктирная линия, выходящая из него, называется линией жизни (lifeline) 4. Это не обозначение отношения в модели, а графический комментарий, призванный направить взгляд читателя диаграммы в правильном направлении. Фигуры в виде узких полосок, наложенных на линию жизни, также не являются изображениями моделируемых сущностей. Это графический комментарий, показывающий отрезки времени, в течении которых объект владеет потоком управления (execution occurrence) 5 или другими словами имеет место активация (activation) объекта. Составные шаги взаимодействия(combined fragment) 6 позволяют на диаграмме последовательности, отражать и алгоритмические аспекты протокола взаимодействия. Прочие детали нотации диаграммы последовательностей см. в главе 4.

Рис. Нотация диаграммы последовательности

Диаграмма коммуникации (communication diagram) ‒ способ описания поведения, семантически эквивалентный диаграмме последовательности.

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

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

На рисунке показаны основные элементы нотации, применяемые на диаграмме коммуникации.

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

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

Рис. Нотация диаграммы коммуникации

Диаграмма компонентов (component diagram) ‒ показывает взаимосвязи между модулями (логическими или физическими), из которых состоит моделируемая система.

Основной тип сущностей на диаграмме компонентов ‒ это сами компоненты 1, а также интерфейсы 2, посредством которых указывается взаимосвязь между компонентами. На диаграмме компонентов применяются следующие отношения:

  • реализации между компонентами и интерфейсами (компонент реализует интерфейс);
  • зависимости между компонентами и интерфейсами (компонент использует интерфейс) 3.

На рисунке показаны основные элементы нотации, применяемые на диаграмме компонентов. Детальное описание приведено в главе 3.

Рис. Нотация диаграммы компонентов

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

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

На рисунке показаны основные элементы нотации, применяемые на диаграмме размещения. Для того чтобы показать, что одна сущность является частью другой, применяется либо отношение зависимости  5, либо фигура одной сущности помещается внутрь фигуры другой сущности 6. Детальное описание диаграммы приведено в главе 3.

Рис. Нотация диаграммы размещения


1.6. Специальные диаграммы >>

Моделирование на UML. Ф.Новиков, Д.Иванов.

Rational Rose 2000 и UML. Визуальное моделирование.

[ Содержание ] [ Назад ] [ Далее ]


Глава 8. Изучение наследования

Наследование

Наследованием (inheritance) называется такое отношение между классами, когда один класс использует часть структуры и/или поведения другого или нескольких классов. При наследовании создается иерархия абстракций, в которой подкласс (subClass) наследуется от одного или нескольких суперклассов (superClass). Наследование также называют иерархией типа «такой же, как» (is-a) или «такого вида, как» (kind-of). Подкласс наследует все атрибуты, операции и отношения, определенные в каждом его суперклассе. Значит, все атрибуты и операции, определенные на верхнем уровне иерархии, будут унаследованы классами на более низких ее уровнях. В подкласс могут быть добавлены дополнительные атрибуты и операции, применяемые только на данном уровне иерархии. Подкласс может содержать собственную реализацию унаследованной операции. Так как отношение наследования не является отношением между различными объектами, оно не имеет названия, не использует названия ролей и к нему не применяется понятие мощности.

На количество классов в иерархии наследования ограничений не существует. Однако на практике в программах, созданных с помощью C++, обычно используется от трех до пяти уровней, тогда как в приложениях, написанных на языке Smalltalk, — немного больше.

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

Существует два способа определения наследования — обобщение и специализация. В любых разрабатываемых системах обычно используются оба метода.

Обобщение

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

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

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

Специализация

С помощью специализации (specialization) создаются подклассы, которые уточняют суперкласс — добавляют структуру и поведение. Такой метод наследования применяется, когда уже существует определенный класс. Подкласс создается, чтобы адаптировать поведение существующего класса. Например, в систему регистрации допускается добавить функцию, посредством которой обеспечивались бы бесплатными курсами. Новый подкласс (SeniorCitizen) может быть добавлен в иерархию класса (Regist-rationllser) для хранения данных, относящихся к .

В подклассе операции могут быть перекрыты (overridden). Однако подкласс не должен ограничивать операции, определенные в его суперклассах, то есть не должен урезать их структуру и поведение.

Последовательность создания отношения наследования в программе Rational Rose:

  1. Откройте диаграмму классов, на которой будет изображена иерархия наследования.
  2. Щелкните по кнопке Class (Класс) на панели инструментов, а затем по диаграмме, чтобы поместить на нее класс.
  3. Введите имя класса. Класс также может быть создан в браузере и перемещен на диаграмму.
  4. Щелкните по кнопке Generalization (Обобщение) на панели инструментов.
  5. Щелкните по подклассу и проведите линию связи к суперклассу.
  6. Повторите последнее действие для других подклассов.

Отношение наследования показано на рис. 8.1.

Рис. 8.1. Отношение наследования

Дерево наследования

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

Например, одним из дискриминаторов для класса (Course) является место обучения. Классы очный (OnCampusCourse) и OffSiteCourse) могут стать подклассами для класса , созданными на основе этого дискриминатора. Отношения наследования для всех подклассов, полученных от одного дискриминатора, представляются в виде дерева. Другим подклассом класса может стать класс . Этот подкласс не будет частью дерева наследования, так как он принадлежит другому дискриминатору — типу предмета. Следует внимательно подходить к вопросу определения нескольких дискриминаторов для одного класса. Например, что произойдет, если обязательный предмет тоже очный? Является ли это примером множественного наследования? Не нужно ли здесь применить агрегацию? В ходе анализа и проектирования ответы на эти вопросы постепенно позволят получить законченную структуру модели.

Для создания дерева наследования в программе Rational Rose:

  1. Откройте диаграмму классов, на которой будет изображена иерархия наследования.
  2. Щелкните по кнопке Class на панели инструментов, а затем по диаграмме, чтобы поместить на нее класс.
  3. Введите имя класса. Класс также может быть создан в браузере и перемещен на диаграмму.
  4. Щелкните по кнопке Generalization на панели инструментов.
  5. Щелкните по подклассу и проведите линию связи к суперклассу.
  6. Для каждого подкласса, являющегося частью дерева наследования: щелкните по кнопке Generalization на панели инструментов, щелкните по подклассу и проведите линию обобщающей связи к значку наследования (в виде треугольника).

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

Древовидное отношение наследования показано на рис. 8.2.

Рис. 8.2. Дерево наследования

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

После создания суперкласса атрибуты, операции и отношения размещают по возможности на самом высоком уровне иерархии. Какие же свойства необходимо перенести? Давайте посмотрим на иерархию с базовым классом . Атрибуты, операции и отношения для подклассов показаны на рис. 8.3.

Рис. 8.3. Иерархия наследования для класса пользователь

Так как атрибуты (name) и (IDNumber) одинакового формата, их можно с уверенностью перенести в суперкласс (RegistrationUser). Оба класса связаны с классом (CourseOffering). Для этого отношения существуют два варианта:

  • сохранить отношения на уровне подклассов;
  • сделать отношение на уровне суперкласса со значением мощности, учитывающим объекты и (один объект связан с объектами в количестве от 4 до 11). Кроме того, здесь накладывается дополнительное ограничение: один из объектов должен быть .

Какой из этих вариантов является правильным? Оба. Какой из них лучше использовать? Зависит от ситуации. Если требуется, чтобы объект «знал» всех и , то хранить единый список с такой информацией наверняка будет удобнее. В этом случае воспользуйтесь вторым вариантом. С другой стороны, если нужно знать только или только , подойдет первый вариант. Все зависит от требований к системе. В подобных ситуациях следует тщательно изучить функции и сценарии, чтобы определить нужное поведение.

Для перемещения атрибутов и операций в программе Rational Rose:

  1. В окне браузера щелкните по значку «+» слева от имени подкласса, чтобы раскрыть список его свойств.
  2. Выберите атрибут или операцию, которую нужно переместить.
  3. Перетащите с помощью мыши атрибут или операцию на суперкласс.
  4. Удалите данный атрибут или операцию из других подклассов.
  5. Таким же образом переместите другие необходимые атрибуты из подклассов в суперкласс.

Иерархия наследования после переноса атрибутов показана на рис. 8.4.

Рис. 8.4. Атрибуты и операции, перемещенные в суперкласс

Одиночное и множественное наследование

При одиночном наследовании класс содержит единственный набор потомков, то есть одну цепочку суперклассов (например, легковая машина — это автомобиль, а автомобиль — средство передвижения). Множественное наследование включает более одной цепочки суперклассов (машина-амфибия — это автомобиль, автомобиль — средство передвижения, в то же время машина-амфибия — это лодка, а лодка — средство передвижения). При множественном наследовании возникает ряд проблем, в частности конфликт имен и несколько копий унаследованных свойств. Способ решения таких проблем выбирается в зависимости от языка программирования: виртуальные базовые классы в C++ или отсутствие поддержки множественного наследования в PowerBuilder.

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

Наследование и агрегация

Наследование часто используется не по назначению. Существует мнение, что «чем больше я буду его использовать, тем лучше станет мой код». Это заблуждение. В Действительности неправильное применение наследования может привести к проблемам. Например, может учиться очно или заочно. Создадим суперкласс (Student) и два подкласса — очного отделения (FulltimeStudent) и заочного отделения (ParttimeStudent). Во время работы такой структуры наверняка возникнут определенные проблемы. Что случится, если:

  • решит перейти на заочное? Это значит, что объекту придется сменить класс;
  • будет добавлена еще одна размерность (например, , )? Здесь понадобятся новые подклассы для представления информации о стипендии, а также множественное наследование для поддержки всех комбинаций (, и т.д.).

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

Рис. 8.5. Наследование в сравнении с агрегацией

Резюме

Наследование позволяет создавать иерархию классов, когда общая структура и поведение разделяются между ними. Термин «суперкласс» характеризует класс, содержащий общую информацию.

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

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


[ Содержание ] [ Назад ] [ Далее ]

Зависимости

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

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

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

Обобщения

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

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

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

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

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

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

Ассоциации

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

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

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

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

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

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

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

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

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

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

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

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

По сути, агрегация – это особый вид ассоциации, поэтому изображается она линией простой ассоциации, к которой добавлен пустой ромбик со стороны объекта-целого (рис. 6).

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

.

Отношения между классами и объектами

Последнее обновление: 31.10.2015

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

Наследование

Наследование является базовым принципом ООП и позволяет одному классу (наследнику) унаследовать функционал другого класса (родительского). Нередко отношения наследования еще называют генерализацией или обобщением. Наследование определяет отношение IS A, то есть «является». Например:

class User { public int Id { get; set; } public string Name { get; set; } } class Manager : User { public string Company{ get; set; } }

В данном случае используется наследование, а объекты класса Manager также являются и объектами класса User.

С помощью диаграмм UML отношение между классами выражается в незакрашенной стрелочке от класса-наследника к классу-родителю:

Реализация

Реализация предполагает определение интерфейса и его реализация в классах. Например, имеется интерфейс IMovable с методом Move, который реализуется в классе Car:

public interface IMovable { void Move(); } public class Car : IMovable { public void Move() { Console.WriteLine(«Машина едет»); } }

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

Ассоциация

Ассоциация — это отношение, при котором объекты одного типа неким образом связаны с объектами другого типа.

Например, объект одного типа содержит или использует объект другого типа. Например, игрок играет в определенной команде:

class Team { } class Player { public Team Team { get; set; } }

Класс Player связан отношением ассоциации с класом Team. На схемах UML ассоциация обозначается в виде обычно стрелки:

Нередко при отношении ассоциации указывается кратность связей. В данном случае единица у Team и звездочка у Player на диаграмме отражает связь 1 ко многим. То есть одна команда будет соответствовать многим игрокам.

Агрегация и композиция являются частными случаями ассоциации.

Композиция

Композиция определяет отношение HAS A, то есть отношение «имеет». Например, в класс автомобиля содержит объект класса электрического двигателя:

public class ElectricEngine { } public class Car { ElectricEngine engine; public Car() { engine = new ElectricEngine(); } }

При этом класс автомобиля полностью управляет жизненным циклом объекта двигателя.

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

На диаграммах UML отношение композиции проявляется в обычной стрелке от главной сущности к зависимой, при этом со стороны главной сущности, которая содержит, объект второй сущности, располагается закрашенный ромбик:

Агрегация

От композиции следует отличать агрегацию. Она также предполагает отношение HAS A, но реализуется она иначе:

public abstract class Engine { } public class Car { Engine engine; public Car(Engine eng) { engine = eng; } }

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

Отношение агрегации на диаграммах UML отображается также, как и отношение композиции, только теперь ромбик будет незакрашенным:

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

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

НазадСодержаниеВперед

Добавить комментарий

Закрыть меню