- Абстрактный класс
- Виды отношений
- Идентификатор
- Класс
- Классы, отвечающие за графику
- Кратность
- Методы класса
- Моделе-ориентированное проектирование информационных систем на uml
- Назначение диаграммы классов
- Отношение агрегации
- Отношение ассоциации
- Отношение зависимости
- Отношение композиции
- Отношение наследования
- Поля класса
- Постановка задачи и её анализ
- Предисловие
- Процедура тестирования
- Статический класс
- Тип поля
- Уровень видимости
- Шпаргалки по uml
- Экзамены по uml от других вендоров
Абстрактный класс
Класс, который является базовым для других классов и объекты которого мы не собираемся создавать, называют абстрактным. Абстрактный класс на диаграмме изображается так же, как и обычной класс, однако имя такого класса должно быть записано курсивом.
В UML принято соглашение, согласно которому все элементы, относящиеся к абстрактному классу, должны быть помечены курсивом (жирный шрифт при этом сохраняется).
Виды отношений
Давайте начнём рассматривать различные отношения между классами на диаграмме. Нами будут рассмотрены следующие соединительные линии:
Обозначение каждого вида отношения представлено на рисунке ниже. Далее мы начнём рассматривать каждое отношение в подробностях.

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

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

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

с математическими выражениями.
Пока что эта диаграмма не даёт никакого понимания того, как будет устроена наша система, однако к концу статьи диаграмма значительно преобразится.
Классы, отвечающие за графику
Помните, мы в начале статьи договорились, что у нас будет две диаграммы: одна для классов, отвечающих за работу с функциями, другая – для классов, отвечающих за графику? Настало время построить вторую диаграмму. Результат представлен на картинке ниже.
Слишком много непонятных классов
Кратность
Кратность (от англ. “multiplicity”) – интервал, определяющий диапазон количества элементов в массиве. Если для поля указана кратность, то его следует считать массивом. Количество элементов в таком массиве и будет определяться указанным интервалом.

Пояснение к использованию кратности
Для кратности указывают одно или два значения:
Может случиться так, что мы захотим показать, что в массиве может храниться неограниченное количество элементов. В таком случае верхняя граница n заменяется символом *.
Примеры интервалов:
Наиболее часто используют кратность [0..*] или [1..*]. Можно заметить, что динамические структуры данных вообще очень удобны в использовании. В нашей статье мы откажемся от использования кратности, а будем использовать такие коллекции: связный список (List) и ассоциативный массив (Map).
С использованием кратности мы ещё столкнёмся, когда будем знакомиться с различными типами отношений. Теперь, когда мы немного познакомились с правилами описания полей классов, давайте опишем некоторые поля для классов нашего проекта.

Чтобы отличать статические элементы класса от обычных, статические поля и методы будут подчёркиваться.
Назначение каждого поля построенных классов
Методы класса
Снова разберём наш пример с классом Customer. На этот раз обратим внимание на третью секцию – секцию методов.
Описание методов очень похоже на описание полей класса. На рисунке ниже представлен общий вид описания метода класса.
Аргументы методов в общем случае описываются следующим образом:

в указанном формате.
Теперь давайте добавим на нашу основную диаграмму методы классов.
Назначение каждого метода построенных классов
Моделе-ориентированное проектирование информационных систем на uml
Нет, запись трансляции купить нельзя, мы продаём обучение, а не записи.
Просмотр записей наблюдений за тем, как пловцы под руководством тренера плывут по дорожкам 4 часа подряд учебного эффекта для зрителя не создаёт 🙁
Для обучения, помимо инструктажа по записи, необходимо:
- выполнить ту деятельность, по которой вы получили инструктаж;
- получить обратную связь на результаты вашей деятельности;
- выполнить работу над ошибками, чтобы сформировать правильный навык и закрепить его
Поэтому наш курс состоит из практических занятий, а не вебинаров.
Мы даём доступ к записям отдельных только для тех, кто не по своей воле пропустил 1-2 занятия.
Приходите в следующий раз или записывайтесь на индивидуальный формат.
Назначение диаграммы классов
Диаграмма классов (от англ. “class diagram”) предназначена для представления внутренней структуры программы в виде классов и связей между ними.
Все сущности реального мира, с которыми собирается работать программист, должны быть представлены объектами классов в программе. При этом у каждого класса должно быть только одно назначение и уникально осмысленное имя, которое будет связано с этой целью.
Взаимосвязь диаграммы классов с другими диаграммами
Диаграмма классов UML тесно связана с другими диаграммами, поскольку в них используются экземпляры классов (объекты), описанные на диаграмме классов. Например, на диаграмме кооперации (англ. “cooperation diagram”) показывается структурные связи при взаимодействии объектов, а на диаграмме последовательности (англ. “sequence diagram”) изображается последовательность обмена сообщений между объектами.
Отношение агрегации
Отношение агрегации между двумя классами показывает, что один из них включает в себя другой класс в качестве составной части. При этом класс-часть может и существовать обособленно от класса-целого (далее мы раскроем смысл этой фразы).
В переводе с английского, слово aggregation означает соединение частей. Это значение очень точно отражает суть данного отношения – показать, из каких частей состоит класс.
В целом, смысл этого отношения достаточно условен. Может показаться, что определение отношения агрегации «один класс включает в себя другой класс» означает примерно следующее:
class A
{
class B
{
};
…
}; На самом деле, это отношение означает, что объект одного класса включает в себя в качестве составной части объект другого класса.

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

другие для вывода результатов.
В общем случае, использование отношения ассоциации выглядит следующим образом:
Как вы можете заметить, стрелка ассоциации направлена от класса пользователя к классу владельцу используемой функциональности. Для пояснения того, каким образом один класс использует другой класс, вы можете описать данный процесс в вспомогательном тексте.
Обратите внимание на кратность ассоциации, которая расположена под стрелкой. С кратностью мы уже встречались ранее. Здесь у нее несколько иное значение. Кратность ассоциации обозначает количество объектов, которые участвуют во взаимодействии. Как показано на рисунке выше, во взаимодействии могут участвовать от m до n пользователей и от q до r владельцев.

Если кратность ассоциации не указана, будет подразумеваться кратность [0..*]. В случае со статическими классами кратность не указывается (можно считать, что там указана кратность [1].
Избегайте использования отношения ассоциации в обе стороны, как это показано на рисунке ниже. Такое взаимодействие классов можно считать ярким примером спагетти-кода. В случае ошибки очень сложно будет обнаружить, что послужило ей причиной.
Обозначение отношения ассоциации
Строго говоря, отношение ассоциации изображают сплошной линией без стрелок. Например, на различных сайтах вы, скорее всего, могли видеть следующие примеры.

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

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

Стрелка отношения зависимости направлена от зависимого класса к независимому.
Объекты класса Graph зависят от изменений в объектах класса MathExpression, поскольку, на самом деле, в объекте Graph хранится указатель на объект класса MathExpression. Поэтому мы можем считать, что график «знает» обо всех изменениях внутри математического выражения (изменение тела функции, изменение границ значений переменной, изменение значения параметров и т.д.).
Отношение между этими двумя классами как бы соединяет две диаграммы воедино. Все классы нашей первой диаграммы «работают» на объекты класса MathExpression. Людям, работающим с графической частью приложения, нужно знать лишь об этом классе, что существенно снижает сложность. В результате наша вторая диаграмма приобретает следующий вид.
Отношение композиции
Отношение композиции является частным случаем отношения агрегации. Однако у него есть одно отличие – классы-части, которые он соединяет с классом-целым, не могут существовать обособленно.
Одним из переводов слова composition является слово смесь. Если допустить, что из смеси не получится получить исходные компоненты, то это хорошо помогает понять, что части, соединённые отношением композиции не могут существовать сами по себе.
Давайте в качестве примера рассмотрим окно интерпретатора Python.
Понятное дело, что ни полоса прокрутки (ScrollBar), ни заголовок окна (Title), ни поле ввода команд (TextInput) не могут существовать отдельно от окна программы (Window). Это можно изобразить на диаграмме классов следующим образом.
В нашей диаграмме объекты классов FunctionBox и ConstantBox не могут существовать отдельно от их контейнеров. Кроме того, объекты класса Graph тоже не могут существовать обособленно от координатной плоскости.
Вот и всё! Мы рассмотрели достаточно элементов диаграммы классов, чтобы начать делать собственные диаграммы классов.
P.S. Спасибо всем, кто дошёл до этого момента. Статья получилась очень массивной, поскольку хотелось разобрать все основные элементы на практическом примере.
Отношение наследования
Прежде чем мы начнём изучать данное отношение, проясним один момент. Как вы можете видеть, данное отношение имеет два названия: отношение обобщения и отношение наследования. В терминах ООП принцип наследования является очень важной вещью. Чтобы не вносить путаницу в дальнейшее повествование, давайте договоримся использовать только второе название – отношение наследования – применительно к диаграмме классов.
Итак, отношение наследования используется, чтобы показать, что один класс является родителем (базовым классом или суперклассом) для другого класса (потомка, производного класса).
Если вы работали с какой-нибудь библиотекой для создания графического интерфейса (OpenGL в чистом виде не в счёт!), вы могли заметить, что все классы графических элементов обычно выстраиваются в цепочку наследования. Например, взгляните на цепочку наследования классов фреймворка Qt5, представленную на рисунке ниже.

Полная версия диаграммы
Полную версию диаграммы вы можете посмотреть по ссылке
Разумеется, такие цепочки наследования просто необходимы, поскольку различные виджеты (графические элементы) имеют схожие свойства и поведение. В нашем приложении классы виджетов тоже были созданы на основе нескольких базовых классов: QWidget и QDialog. Давайте покажем это на диаграмме.
Мы свернули классы ради экономия места. В дальнейшем мы также будем это делать, поскольку нас будет интересовать именно отношения между классами, а не их поля и методы. Заметьте, что в большинстве наших классов мы не можем обойтись без класса QWidget и QDialog, однако его использование приводит к беспорядку.
Давайте договоримся, что больше мы не будем изображать эти два базовых класса, чтобы избежать проблем с читабельностью диаграммы. Тем не менее, мы будем иметь в виду, от каких классов наследуются оставшиеся.
Поля класса
Вернёмся к нашему примеру с классом Customer. Обратите внимание на центральную секцию.
Давайте рассмотрим первую строчку. Что вообще означает запись “- balance: Integer”? Сейчас будем разбираться.
В общем случае, каждое поле класса должно описываться следующим образом:

Нами в данной статье не будет рассмотрено использование свойств в полях класса, поскольку это достаточно специфичная тема.
Постановка задачи и её анализ
Представьте, что мы хотим разработать программу для построения графиков функций. Давайте кратко изобразим основной функционал такой программы на диаграмме вариантов использования UML:
Зачем нужен вариант использования “построить график функции”
В своей программе я сделал ставку на то, что пользователь захочет сначала задать все функции, с которыми он захочет работать, а только после этого строить те, которые ему нужны в данный момент.
Разумеется, мы хотим, чтобы наше приложение обладало графическим интерфейсом. На данном этапе разумно будет разбить задачу построения диаграммы на две части:
Построить диаграмму для классов, ответственных за работу с пользовательскими математическими функциями.
Построить диаграмму для классов, ответственных за корректное отображение графических элементов в программе.
Зачем плодить множество диаграмм, когда можно сделать одну большую?
Классы, ответственные за работу с математическими функциями будут предоставлять возможность создавать объекты математических функций и подсчитывать таблицу значений.
Давайте определимся с тем, как мы собираемся работать с функциями. Во-первых, договоримся, что мы будем работать не напрямую с функциями, а только с их телами.
Именно поэтому в этой статье мы будем оперировать термином математическое выражение, а не термином функция.
Компьютер не может оперировать напрямую математическими выражениями, записанными в строке так же просто, как и обычными числами, записанными в коде программы.
Поэтому мы создадим набор классов, которые будут «знать», как работать с такими данными. Упрощённая схема создания математических выражений представлена на рисунке ниже.
Для того чтобы мы могли работать с телом функции, записанным в виде строки, необходимо разбить эту строку на элементарные части. Их чаще всего называют лексемами (от англ. “lexeme”) или токенами (от англ. “token”). В данной статье мы будем использовать термин токен.
Затем из полученного списка токенов мы будем строить постфиксную запись выражения.
На этом этапе математическое выражение мы будем считать обработанным и готовым к работе. Чтобы вычислить значение этого выражения, мы будем подставлять вместе переменной какое-либо действительное значение.
Для удобства работы с нашим приложением нужно добавить возможность определения и использования именованных констант. Например, использование распространённых математических констант, таких как π = 3,141592.. или e = 2,71828.. будет очень удобным для пользователей.
В заключение, хочется отметить, что каждое серьёзной программе необходим механизм обработки ошибок. Наша программа не будет исключением. Пользовательские выражения будут проверяться на корректность математической записи.
Соглашение об именовании объектов и классов
Несмотря на то, что данную статью я пишу на русском языке, на диаграммах мы всё будем описывать на английском языке. Для этого есть две причины:
Когда вы начнёте реализовывать классы, описанные на диаграмме, в коде, вы будете давать им название на английском языке. Разные программисты по-разному могут перевести одно и то же слово. Например, класс “МатематическоеВыражение” некоторые могут перевести как “MathExpression”, другие, исходя из специфика задачи, как “Function” или просто как “Expression”. Таким образом, когда вы начнёте сопоставлять написанные классы с элементами на диаграмме, вы можете запутаться.
Технический английский язык обычно более ёмок, чем русский. Это позволит сократить объём текста на диаграмме.
Давайте подведём итог и выясним, какие классы нам будут нужны для решения поставленной задачи:
Почему все имена классов имеют префикс Math?*
Предисловие
Парадигма объектно-ориентированного программирования (далее просто ООП) повсеместно используется при создании современного программного обеспечения. Модель объектов, заложенная в данную парадигму, способна достаточно точно описывать свойства и возможности сущностей реального мира.
Стандартная библиотека некоторого языка программирования – замечательный сборник полезных утилит. Однако разнообразие решаемых программистами задач так велико, что одной только стандартной библиотекой ограничиться не получится. Программисту часто приходится самому создавать необходимый ему набор функциональности. Это можно сделать, создав пакет функций или набор классов.
Создание собственных классов при разработке программы добавляет в проект новый уровень абстракции, который позволяет определить некоторый функционал системы и работать в дальнейшем только с ним.

«Хорошая абстракция превращает практически неподъемную задачу в две, решить которые вполне по силам. Первая из этих задач состоит в определении и реализации абстракции, а вторая – в использовании этих абстракций для решения текущей проблемы.»
Э.С. Таненбаум
Использование ООП может существенно упросить жизнь программисту. Это достигается за счёт сокрытия особенностей внутренней реализации классов. Программисту остаётся лишь пользоваться её удобствами. Кажется, что ООП – панацея от всех проблем. Однако на практике, если не иметь чёткого представления о том, какие классы нужно реализовать и как ими потом пользоваться, в результате может получиться очень запутанная система, которая начнёт порождать спагетти-коду (от англ. “spaghetti code”), который будет лишь мешаться, когда вы захотите добавить что-то новое в систему.
Чтобы избежать большинства проблем, возникающих при использовании ООП, нужно:
Иметь некоторый опыт создания программ и использования классов.
Строить структурные диаграммы классов.
Первое придёт со временем, а со вторым я могу вас познакомить прямо сейчас. Сегодня мы разберём диаграмму классов UML.
Процедура тестирования
Во время экзамена зона тестирования наблюдается с помощью видеокамер, или же сотрудник учебного центра постоянно находится в помещении и следит за соблюдением правил тестирования. А правила эти состоят в следующем:
- нельзя общаться с другими кандидатами (да и смысла нет – скорее всего, они будут сдавать тесты, отличные от вашего). Обращаться можно только к администратору в случае возникновения вопросов, связанных с процедурой тестирования;
- нельзя пользоваться заметками, книгами и т. д. Ноутбуки, КПК и микрокалькуляторы, естественно, тоже запрещены. Мобильные телефоны перед началом тестирования должны быть выключены;
- сумки, портфели, рюкзаки, записные книжки, сотовые телефоны и другие личные вещи нужно будет оставить вне зоны тестирования – обычно в учебном центре предусмотрен специальный шкаф для хранения таких вещей;
- нельзя списывать с экрана вопросы и ответы (вам предоставят ручку и бумагу, но не для этих целей), выносить их из зоны тестирования или обсуждать с другими кандидатами;
- нельзя пользоваться электронными словарями, а если словарь вам все же необходим, вам предложат его в печатном виде (впрочем, на некоторых экзаменах, имеющих дополнительные 30 мин для неанглоязычных стран, пользование печатными словарями запрещено).
Запомните: если администратор учебного центра уличил вас в нарушении правил, ваш тест будет аннулирован без возмещения затрат! Отметим еще несколько нюансов процедуры тестирования:
- направляясь на экзамен, не забудьте взять с собой паспорт или другой документ, удостоверяющий личность (в некоторых учебных центрах подойдет даже кредитная карточка с фотографией, но лучше не рисковать);
- если вы не пришли на экзамен, то попытка “сгорает” и деньги не возвращаются, а каждая новая попытка также стоит денег вне зависимости от результата (если вы не сдали с первой попытки, вторая обойдется вам в точно такую же сумму);
- если вы опоздали на экзамен, сдать его вы сможете только при наличии в учебном центре свободных мест. Если мест нет, деньги, уплаченные вами, как и в предыдущем случае, не возвращаются;
- вы можете перенести экзамен на другую дату, но об этом нужно сообщить в учебный центр не менее чем за 2 рабочих дня до прежде заявленной даты;
- прийти в учебный центр следует за 10-15 минут до назначенного времени – возможно, вам нужно будет подписать какие-то бумаги, оставить в специально предусмотренном месте личные вещи и т. д.
Статический класс
Класс, в котором есть только статические поля и методы и на основе которого не создаются объекты, называется статическим классом. Чтобы показать на диаграмме, что наш класс статический, нужно добавить к имени модификатор «utility».
Формально, такие модификаторы называется стереотипами. Стереотип – именованный набор свойств. В данном случае, стереотип «utility» означает, что объекты указанного класса не создаются.
По сути, название модификатора «utility» связано с тем, статический класс предоставляет набор утилит, которые могут быть использованы любыми классами, которые в них нуждаются.
В нашей системе классы MathParser, MathFormConverter, MathConstantManager являются статическими, потому что они представляют собой «сборник» полезных функций, которые мы объединили в класс. Давайте изобразим это на нашей диаграмме.

Тип поля
Тип поля (англ. “type of field”) показывает, какой тип имеет данное поле в нашей программе. На ранней стадии проектирования можно и не уточнять, какой тип имеет то или иное поле.
Типы полей обычно привязаны к какому-то конкретному языку программирования, например. Кроме того, в качестве типа поля может быть использован пользовательский тип данных.
Уровень видимости
Уровень видимости (от англ. “visibility”) – свойство поля, которое показывает, из какой части программы можно обратиться к данному полю.

Обычно может принимать следующие значения:
Может показаться, что как-то неудобно для каждого поля указывать его уровень видимости. Почему бы не группировать поля по уровню видимости? Например, именно такой подход используется в языке программирования C . Давайте попробуем напрямую использовать ключевые слова public, private и protected.
Несмотря на удобство такого подхода, мы будем указывать уровень видимости для каждого элемента.
А что будет, если не указывать уровень видимости вовсе?*
Шпаргалки по uml
Мы ни на секунду не засомневались в том, что каждый наш читатель знает, что такое шпаргалка. Хотите верьте, хотите нет, но:
- Автор этих строк писал шпаргалки только один раз в жизни – в далеком уже 1991 году, когда готовился к экзамену по украинскому языку. А в результате так ими и не воспользовался: попалось ли что-то уж очень простое, или смелости не хватило – не помню. А может, все зазубрил до автоматизма…
- Шпаргалки можно использовать в “мирных” целях. Если их пишешь сам, то волей-неволей повторяешь и приводишь в систему весь учебный материал. Если читаешь уже кем-то подготовленные шпаргалки, это помогает быстро “освежить” память, вспомнить или понять что-то на концептуальном уровне, с высоты птичьего полета, выделить главное.
Экзамены по uml от других вендоров
Кроме OCUP существуют и другие программы сертификации, и отдельные экзамены, связанные с UML. Их не так уж много, но они есть. В свое время автор этих строк очень заинтересовался этим вопросом – хотелось попрактиковаться, попробовать сдать тест “подешевле”, прежде чем заказывать UM0-100.
Чуть позже найденная информация пригодилась уже в процессе описания концепции тестирования знаний и навыков UML-моделирования в рамках тренингов, предлагаемых INTSPEI. И после этого вы скажете, что в этом мире бывают случайности?
Информацию о тех экзаменах поUML, которые удалось отыскать, мы разбили на две группы. В первую группу мы выделили экзамены вендоров. Во вторую же попали экзамены от независимых организаций.
Позволим себе несколько комментариев. Как наиболее подходящий для начинающих следует отметить тест IBM 486. В свою бытность преподавателем автор и его коллеги рекомендовали этот тест своим студентам в качестве замены традиционного экзамена по соответствующему курсу (желающих, впрочем, было не так уж много).
Кстати, и на роль пробного теста перед попыткой сдать UM0-100 он тоже неплохо подходит – раньше IBM вообще предлагала бесплатный пробный тест. Сейчас он уже стоит денег, но очень небольших. Правда, тематика теста чуть-чуть шире, чем у UM0-100 (который является лишь первой ступенью сертификации).
Оба теста от Sun являются, по сути, различными вариантами одного и того же экзамена, только форма различается: один – это собственно тест, а второй – создание модели, описанной в полученном задании.
Очень достойные экзамены, но не для студентов: тут предполагается некий опыт в области UML-моделирования и разработки архитектуры ПО. Что же касается майкрософтовской сертификации для архитекторов, то это не для простых смертных, так как цена способна отпугнуть почти любого.
А вот и та самая альтернатива – тесты от независимых организаций:
