М. Фаулер, К. Скотт - UML Основы (1114905), страница 15
Текст из файла (страница 15)
На диаграмме показано, что Заказ может поступить только от одного Клиента, а Клиент в течение некоторого времени может сделать несколько Заказов. Каждый из этих Заказов может содержать несколько Строк заказа, причем каждая Строка заказа должна соответствовать единственному Товару. Каждая из ассоциаций имеет два конца ассоциации; при этом каждый из концов ассоциации присоединяется к одному из классов этой ассоциации. Конец ассоциации может быть явно помечен некоторой меткой. Такая метка называется именем роли.
(Концы ассоциации часто называют ролями. ) Так, например, на рис. 4.1 конец ассоциации, направленной от класса Заказ к классу Строка заказа, имеет название Позиции заказа. Если такая метка отсутствует, концу ассоциации присваивается имя класса-цели; например, конец ассоциации от класса Заказ к классу Клиент может быть назван клиент. Конец ассоциации также обладает кратностью, которая показывает, сколько объектов может участвовать в данном отношении.
На рис. 4.1 символ «*» возле класса Заказ для ассоциации между классами Заказ и Клиент показывает, что с одним клиентом может быть связано много заказов; напротив, символ «1» показывает, что каждый из заказов может поступить только от одного клиента.
В общем случае кратность указывает нижнюю и верхнюю границы количества объектов, которые могут участвовать в отношении. При этом символ «*» означает диапазон Омбес«гояечность: клиент может не сде- 69 Ассоциации лать ни одного заказа, но верхний предел количества заказов, сделанных одним клиентом, никак не ограничен (разумеется, теоретически!). 1 означает диапазон 1..1, то есть заказ должен быть сделан одним и только одним клиентом.
На практике наиболее распространенными вариантами кратности являются «1», «*» и «0..1» (либо ноль, либо единица). В более общем случае для кратности может использоваться единственное число (например, 11 для количества игроков футбольной команды), диапазон (например, 2.,4 для количества игроков карточной игры канаста) или дискретная комбинация нз чисел или диапазонов (например, 2, 4 для количества дверей в автомобиле). С точки зрения спецификации ассоциации представляют собой ответственности классов.
На рис. 4.1 предполагается, что существует один или более методов, связанных с классом Клиент, с помощью которых можно узнать, какие заказы сделал конкретный клиент. Аналогично в классе Заказ существуют методы, с помощью которых можно узнать, какой Клиент сделал конкретный Заказ и какие Строки заказа входят в этот Заказ. Если установить стандартные соглашения по наименованию методов запросов, то, вероятно, я смог бы вывести из диаграммы названия этих методов.
Например, можно принять соглашение, в соответствии с которым взаимно однозначные отношения реализуются посредством метода, который возвращает связанный объект, а многозначные отношения реализуются посредством итератора, указывающего на совокупность связанных объектов. Следуя подобному соглашению, в языке Лака, например, я могу опре- делить следующий интерфейс для класса Заказ: с1ввв Огоег ( риЫ1с Совтоаег Оетсовтоеег(); риЫ1с Эет Оетэгзег(1еев(); (Огс(ег — Заказ, Сиз(отег — Клиент, Ог4егй!лез — Строки заказа) Очевидно, соглашения по программированию могут изменяться от случая к случаю и не затрагивать каждый метод, однако они могут оказаться весьма полезными с точки зрения нахождения вашего собственного стиля разработки.
Ассоциация несет также определенную ответственность за обновление соответствующего отношения. Так, например, должен существовать некоторый способ связи класса Заказ с классом Клиент. Детали этого способа на диаграмме не.показаны; можно было бы включить спецификацию класса Клиент в конструктор для класса Заказ. Или это может быть метод добавитьЗаказ, ассоциированный с классом Клиент. Как мы увидим позже, такой способ связи можно сделать более явным посредством добавления операций в блок класса на диаграмме.
70 Глава 4. Диаграммы классов: основы Однако эта ответственность не распространяется на структуру данных. Рассматривая диаграмму с точки зрения спецификации, я не могу высказать никаких предположений относительно структуры данных для классов. Я не могу сказать, да мне и не следует знать, содержит ли в действительности класс Заказ указатель на класс Клиент или же класс Заказ реализует свою функциональность посредством выполнения некоторого программного запроса к каждому экземпляру класса Клиент, чтобы выяснить, связан ли он с данным классом Заказ.
Диаграмма описывает только интерфейс — и ничего более. Если же модель рассматривается с точки зрения реализации, можно исходить из предположения, что между связанными классами существуют указатели в обоих направлениях. В этом случае диаграмма может нам сказать, что класс Заказ содержит поле, представляющее собой совокупность указателей на класс Строка заказа, а также указатель на класс Клиент. На языке дача мы можем выразить эту ситуацию следующим образом: о1авв Огзег ( ог1часе Сивтоеег оовсоеег; ог1еасе Вес огоегмоев; о1авв Сивсовег ( ог1часе эес огоегв; В атом случае большинство аналитиков предполагают, что с таким же успехом могут выполняться все доступные операции, однако можно быть уверенным в этом, только взглянув на операции класса.
Теперь посмотрим на рис. 4.2. В основном он совпадает с рис. 4.1, за исключением того, что я добавил стрелки к ассоциациям. Эти стрелки показывают направление навигации. В модели спецификации таким способом можно показать, что Заказ обязан ответить на вопрос, к какому Клиенту он относится, а Клиенту нет необходимости отвечать, к какому Заказу он имеет отношение. Вместо симметричных ответственностей мы указываем теперь только односторонние. На диаграмме реализации это будет обозначать, что класс Заказ содержит указатель на класс Клиент, но класс Клиент не имеет указателей на класс Заказ. Как можно увидеть, навигация имеет существенное значение на диаграммах спецификации и реализации.
Однако я не думаю, что она сохранит свою полезность при построении концептуальных диаграмм. На концептуальных диаграммах, которые строятся в самом начале разработки, направления навигации чаще всего отсутствуют. Они появляются при построении диаграмм классов уровня спецификации и реализации. Отметим также, что направления навигации, вероятно, могут отличаться с точки зрения спецификации и реализации. Ассоциации Заказ Клиент датзполтченип номер: Строка цена: Деньги имп адрес Фе Навигагвег резить() ыть() (если Ззкзз.глиент,рейтингКредюз ==«низкий», то значение Закззлплзчен должно быть истинным) Корпоративный клиент Индивидуальный клиент контпоноеИмл рейтинг Кредита лимитКредитз номерКредитнойКалочки (рейтинг Кредите() == «нимнй») напомнить() счетЗзцеслц(Целое) Позиции зекззз отчет О продвжзх 0..1 Строка заказа количествх Целое цена: Деныи удовлетворен: Булев 1 Товар г»мс.
е.2. Диаграмма классов с кавигацией Если навигация указана только в одном направлении, то такая ассоциация называется однонаправленной ассоциацией. У двунаправленной ассоциации навигация указывается в обоих направлениях. Если ассоциация не имеет стрелок навигации, то язык 1)МУ.
трактует это следующим образом: направление навигации неизвестно или ассоциация является двунаправленной. В своем проекте вы можете остановиться на любой из этих трактовок. Сам я предпочитаю трактовать от- Глава 4. Диаграммы классов: основы сутствие стрелок в моделях спецификации и реализации как неопределенное направление навигации.
Двунаправленные ассоциации содержат дополнительное ограничение, которое заключается в том, что эти две навигации являются инверсными (обратными) по отношению друг к другу. Это аналогично обозначению обратных функций в математике. Применительно к рис. 4.2 это означает, что каждая Позиция заказа, связанная с некоторым Заказом, должна быть связана с конкретным исходным Заказом. Аналогично, если взять какую-либо Строку заказа и взглянуть на Позиции заказа, соответствующие связанному с ними Заказу, то в совокупности этих позиций можно обнаружить Строку исходного заказа. Это свойство остается справедливым для любой из трех точек зрения. Существует несколько различных способов задания имен ассоциаций.
Традиционный способ именования ассоциаций, принятый у специалистов по моделированию данных, заключается в использовании фразы с глаголом, так чтобы соответствующее отношение можно было бы использовать в предложении. Большинство специалистов по объектному моделированию предпочитают использовать существительные в качестве имен для роли одного или нескольких концов ассоциации, поскольку такой способ лучше согласуется с ответственностями и операциями.
Некоторые разработчики каждой ассоциации присваивают имя. Я присваиваю ассоциации имя только в том случае, когда это улучшает понимание диаграммы. Мне приходилось видеть довольно много ассоциаций с именами типа «имеет» или «связан с». Если у конца ассоциации отсутствует имя, то я считаю, что оно совпадает с именем соответствующего класса-цели. Ассоциация представляет перманентную связь между двумя объектами. Другими словами, такая связь существует в течение всего жизненного цикла объектов, даже если соединяемые ею экземпляры могут изменяться во времени (или при необязательной ассоциации ее вообще может не быть). Так, например, параметрическая ссылка или создание объекта вовсе не подразумевают какую-либо ассоциацию; эти элементы следует моделировать с помощью зависимостей (см.
главы 6 и Т). Атрибуты Атрибуты очень похожи на ассоциации. На концептуальном уровне атрибут «имя Клиента» указывает на то, что клиенты обладают именами. На уровне спецификации этот атрибут указывает на то, что объект Клиент может сообщить вам свое имя и обладает некоторым способом для установления имени. На уровне реализации объект Клиент содержит некоторое поле для своего имени (называемое также переменной экземпляра или элементом данных). В зависимости от степени детализации диаграммы обозначение атрибута может включать имя атрибута, тип и присваиваемое по умолча- Операции нию значение.