### 9. Классы и отношения между ними

Определение классов

Атрибуты класса

Операции класса

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

Определение ассоциаций классов

Контрольные вопросы и упражнения

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

Два главных элемента диаграммы классов — это классы и их основные отношения.

### Определение классов

Класс (class) — абстрактное описание множества однородных объектов, имеющих одинаковые атрибуты, операции и отношения с объектами других классов. Каждый класс должен иметь имя, уникальное в своем контексте.

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

Рисунок 9.1 – Варианты графического изображения класса на диаграмме классов

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

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

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

Класс может иметь или не иметь экземпляров или объектов. В зависимости от этого в языке UML различают конкретные и абстрактные классы.

Конкретный класс (concrete class) — класс, на основе которого могут быть непосредственно созданы экземпляры или объекты.

Рассмотренные выше обозначения относятся к конкретным классам. От них следует отличать абстрактные классы.

Абстрактный класс (abstract class) — класс, который не имеет экземпляров или объектов. Для обозначения имени абстрактного класса используется наклонный шрифт (курсив). В языке UML принято общее соглашение о том, что любой текст, относящийся к абстрактному элементу, записывается курсивом. Это имеет принципиальное значение, поскольку является семантическим аспектом описания абстрактных элементов языка UML.

В некоторых случаях необходимо явно указать, к какому пакету относится тот или иной класс. Для этой цели используется специальный символ разделитель – двойное двоеточие - ( ::). Синтаксис строки имени класса в этом случае будет следующий: <Имя пакета>::< Имя класса >. Другими словами, перед именем класса должно быть явно указано имя пакета, к которому его следует отнести. Например, если определен пакет с именем Банк, то класс Счет в этом банке может быть записан в виде: Банк::Счет.

### Атрибуты класса

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

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

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

<квантор видимости> <имя атрибута> [кратность] :

<тип атрибута> = <исходное значение> {строка-свойство}.

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

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

Символ " + " – обозначает атрибут с областью видимости типа общедоступный ( public ). Атрибут с этой областью видимости доступен или виден из любого другого класса пакета, в котором определена диаграмма.

Символ " # " – обозначает атрибут с областью видимости типа защищенный ( protected ). Атрибут с этой областью видимости недоступен или не виден для всех классов, за исключением подклассов данного класса.

Символ " - " – обозначает атрибут с областью видимости типа закрытый ( private ). Атрибут с этой областью видимости недоступен или не виден для всех классов без исключения.

И, наконец, символ " ~ " - обозначает атрибут с областью видимости типа пакетный ( package ). Атрибут с этой областью видимости недоступен или не виден для всех классов за пределами пакета, в котором определен класс -владелец данного атрибута.

Квантор видимости может быть опущен. Его отсутствие означает, что видимость атрибута не указывается. Эта ситуация отличается от принятых по умолчанию соглашений в традиционных языках программирования, когда отсутствие квантора видимости трактуется как public или private. Однако вместо условных графических обозначений можно записывать соответствующее ключевое слово: public, protected, private, package.

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

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

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

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

Если в качестве кратности указывается единственное число, то кратность атрибута принимается равной данному числу. Если же указывается единственный знак " * ", то это означает, что кратность атрибута может быть произвольным положительным целым числом или нулем. В языке UML кратность широко используется также для задания ролей ассоциаций, составных объектов и значений атрибутов. Если кратность атрибута не указана, то по умолчанию в языке UML принимается ее значение равное [1..1], т.е. в точности 1.

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

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

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

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

Знак " / " перед именем атрибута указывает на то, что данный атрибут является производным от некоторого другого атрибута этого же класса.

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

### Операции класса

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

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

    <квантор видимости> <имя операции>(

                     список параметров):

    <выражение типа возвращаемого значения>

               {строка-свойство}

Квантор видимости, как и в случае атрибутов класса, может принимать одно из четырех возможных значений и, соответственно, отображается при помощи специального символа либо ключевого слова. Символ " + " обозначает операцию с областью видимости типа общедоступный ( public ). Символ " # " обозначает операцию с областью видимости типа защищенный ( protected ). Символ " - " используется для обозначения операции с областью видимости типа закрытый ( private ). И, наконец, символ " ~ " используется для обозначения операции с областью видимости типа пакетный ( package ).

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

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

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

    <направление параметра> <имя параметра>:

     <выражение типа> =

         <значение параметра по умолчанию>.

Параметр (parameter) — спецификация переменной операции, которая может быть изменена, передана или возвращена.

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

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

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

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

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

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

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

Рисунок 9.2 – Обозначения множественности и значки отношений между классами

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

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

Значок агрегирования обозначает отношение "целое/часть" и получается из значка ассоциации добавлением закрашенного кружка на конце, обозначающем агрегат. Экземпляры класса на другом конце стрелки будут в каком-то смысле частями экземпляров класса-агрегата. Разрешается рефлексивная и циклическая агрегация. Агрегация не требует обязательного физического включения части в целое.

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

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

### Определение ассоциаций классов

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

Связи между классами (ассоциации) определяются в два этапа:

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

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

Добавим связи к классам, принимающим участие в варианте использования Register for Courses. Ha рис. 9.3 показаны только классы-сущности. Агрегация между классами Student и Schedule отражает тот факт, что каждый график является собственностью конкретного студента, принадлежит только ему. Предполагается также, что в системе будет храниться не только график текущего семестра, но и все графики студента за разные семестры. Между классами Schedule и CourseOffering введены две ассоциации, поскольку конкретный курс может входить в график студента в качестве основного (не больше четырех курсов) и альтернативного (не больше двух курсов). К классу Student добавлены два новых подкласса — FulltimeStudent (студент очного отделения) и ParttimeStudent (студент вечернего отделения).

Рисунок 9.3 – Диаграмма Entity Classes (классы-сущности)

На рис. 9.4 показаны ассоциации-классы, представляющие свойства связей между классами Schedule и CourseOffering. Ассоциация, связывающая график и альтернативный курс, имеет только один атрибут — статус курса в конкретном графике (status), который может принимать значения "включен в график", "отменен", "внесен в список курса" и "зафиксирован в графике". Если курс в процессе закрытия регистрации переходит из альтернативного в основные, то к соответствующей ассоциации добавляется атрибут "оценка" (grade). Таким образом, ассоциация-класс PrimaryScheduleOfFeringlnfo наследует свойства ассоциации-класса ScheduleOfferinglnfo (атрибуты и операции, содержащиеся в этом классе, относятся как к основным, так и к альтернативным курсам) и добавляет свои собственные (оценка и окончательное включение курса в график могут иметь место только для основных курсов), что показано с помощью связи обобщения.

Рисунок 9.4 – Диаграмма CourseOfferinglnfo (пример ассоциаций-классов)

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

Общие рекомендации по построению диаграмм классов

• использовать зависимость, только если моделируемое отношение не является структурным;

• использовать обобщение, только если имеет место отношение типа "является";

• располагать элементы так, чтобы свести к минимуму число пересекающиеся линий;

• пространственно организовывать элементы так, чтобы семантически близкие сущности располагались рядом;

• чтобы привлечь внимание к важным особенностям диаграммы, использовать примечания (комментарии) и цвет;

Примечание не оказывает влияния на семантику, то есть не изменяет структуру модели. Можно включить в примечание гиперссылку на Web-страницу, связать его с другим документом либо встроить документ в него. Таким образом, UML можно использовать для организации всех артефактов, создаваемых или используемых в процессе разработки. Примечание можно присоединять не только к одному, но и к нескольким элементам.

Рисунок 9.5 – Полная диаграмма классов варианта использования "Зарегистрироваться на курсы"

### Контрольные вопросы и упражнения

1. Что такое класс в объектно-ориентированном анализе? Какие бывают типы классов?

2. Перечислите возможные типы отношений между классами.

3. Что такое кратность отношений между классами.

4. Охарактеризуйте механизм определения операций и ассоциаций классов.

5. Постройте диаграмму классов для произвольной предметной области. Установите отношения разных типов между классами и определите их кратность.