Обычно программы, которые написаны быстро, на коленке и без особых раздумий, недолговечны. Их структура инертна и неудобна, её тяжело расширять и поддерживать, а баги плодятся вдоль и поперёк. Вместе с тем, над такими программами сложно работать в команде.
Чтобы избежать хаоса в программах, хорошенько продумать их структуру, а также передавать свои архитектурные идеи другим, программисты делают наброски и схемы программ, которые им предстоит разработать. Вот только рисует каждый по-своему и обозначения у каждого тоже свои. Чтобы схему одного мог понять другой, умные дяди создали специальный язык моделирования – UML.
Давайте узнаем, что это за язык моделирования, что такое UML-диаграммы классов и как их применять в Java.
Unified Modeling Language
UML (Unified Modeling Language) – это унифицированный язык моделирования. Он используется для проектирования программных систем. Кроме того, его применяют, чтобы показывать свои мысли и идеи другим. UML представляет из себя набор правил и нотаций, которые применимы сразу в разных языках программирования.
Почему бы не записывать и рассказывать это всё обычными словами? Зачем какие-то рисунки и схемы? Проблема с текстами заключается в том, что они требуют дополнительного времени. В сущности, тексты создают лишнюю нагрузку на мозг. Особенно, когда текст читается людьми из разных команд или отделов. Вместо этого использование UML-диаграмм позволяет кратко и наглядно представить основные концепции. Это упрощает понимание как разработчикам, так и представителям QA и управляющим проектом. Одна диаграмма может заменить кучу слов.
В UML есть около 14 типов диаграмм. Это количество может изменяться от стандарта к стандарту. Самые распространённые – диаграмма классов, диаграмма вариантов использования (Use Case), диаграмма состояний, диаграмма последовательности. Поговорим о диаграммах классов.
Базовые правила диаграммы классов
Диаграмма классов графически представляет структуру системы классов, их поля и методы, а также межклассовые отношения. Она помогает показать, как компоненты системы общаются друг с другом.
UML-диаграммы классов предрекают, как понимать прямоугольники на схемах, какие классы с какими связывать пунктирной линией, а какие сплошной, как обозначить public, protected или private поля классов и так далее. Все эти правила помогают человеку, рассматривающему диаграмму классов, понять, как работает система, написанная в парадигме ООП.
Разберёмся в графическом представлении: какие есть обозначения в UML-диаграммах классов. В UML каждый класс представляется прямоугольником, который разделяется на три горизонтальные секции:
- Верхняя секция – здесь указывается имя класса. Имя класса обычно пишется в верхнем регистре.
- Средняя секция – в этой секции указываются атрибуты класса. Они отображаются в формате “модификатор доступа имя_атрибута: тип_данных”. Модификаторы доступа обозначаются следующим образом:
- + (public) для атрибутов, доступных извне класса.
- – (private) для атрибутов, доступных только внутри класса.
- # (protected) для атрибутов, доступных внутри класса и его подклассов.
- Нижняя секция – здесь перечисляются методы класса. Методы указываются в формате “модификатор доступа имя_метода(параметры): тип_возвращаемого_значения”. Здесь используются те же модификаторы доступа (+, -, #) для указания доступности методов.
Посмотрим, что можно понять из этой схемы класса. Video – это название класса. У него есть 4 приватных поля:
- Качество видео, переменная quality типа Quality. Quality – это некий класс или перечисление, и отвечает Quality за классификацию качества видео. Для диаграммы классов нам совершенно необязательно знать, каким конкретно образом реализуется представление информации о качестве видео. Мы в любом случае можем к нему обращаться.
- Длина видео в секундах, переменная lengthInSec типа int. Здесь всё понятно – длина видео, целочисленное значение, записана в секундах.
- Название видео, title типа String – это строка, хранящая название видео.
- Описание видео, description типа String содержит в себе текст, описывающий видео.
Перейдём к методам. Так сложилась судьба, что они все публичные.
- Изменить название видео – метод changeTitle() принимает один параметр типа String. Параметр отражает название, на которое нужно изменить текущее. Метод ничего не возвращает.
- Изменить описание – метод changeDescription() принимает один параметр типа String, который содержит новое описание видео. Метод также не возвращает какое-либо значение.
- Получить статистику по видео – метод calcStatistics(), который параметров не принимает. Однако он возвращает некий объект класса Statistic, по всему видимому хранящий разностороннюю статистику о видео. На UML диаграммах классов мы можем апеллировать к другим классам. Нам совершенно необязательно раскрывать подробности о них.
- Удалить видео – метод delete(), он ничего не принимает и ничего не возвращает. Но зато удаляет это видео.
Посмотрите, сколько текста пришлось написать для описания класса, и сколько этого текста на диаграмме. Как видите, разница потрясающая. Это мы пока с базовыми правилами разбираемся.
Давайте посмотрим, как изображённый на диаграмме класс может выглядеть в коде на Java. Для методов обойдёмся без реализаций – это же проектирование, а не конкретные решения. Перед классом расположим javadoc-комментарий – один из трёх видов комментариев в Java.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/** * класс, представляющий видеоролик со своим названием, * продолжительностью, описанием, качеством * * @author Катя Левкович * @version 1.0, 11.09.2023 */ public class Video { private Quality quality; private int lengthInSec; private String title; private String description; public void changeTitle(String title) { //TODO: написать реализацию метода } public void changeDescription(String description) { //TODO: написать реализацию метода } public Statistic calcStatistics() { //TODO: написать реализацию метода } public void delete() { //TODO: написать реализацию метода } } |
Кроме этих обозначений, есть ещё парочку важных моментов.
Интерфейсы помечаются префиксом <<interface>> перед их названием.
Все абстрактные элементы (классы и методы) пишутся курсивным шрифтом. Названия статических (static) полей и методов помечаются подчёркиванием.
Отношения между классами
Диаграммы классов были бы не диаграммами классов, если бы не позволяли показывать межклассовые связи. Для обозначения связей используются стрелки, которые соединяют классы. Виды отношений:
Как отличить разные связи (отношения) между классами на UML-диаграмме классов:
- Ассоциация (Association), отношение, при котором объекты одного типа неким образом связаны с объектами другого типа. Например, объект одного типа содержит или использует объект другого типа. Связь обычно представляется прямой линией, соединяющей два класса. Иногда добавляют наконечник стрелки, чтобы показать, в каком направлении идёт связь. Также при использовании ассоциаций часто добавляют количества соотносимых классов. Например, класс Car связан отношением 1..4 к классу Wheel, потому что машина ассоциирована с четырьмя колёсами. Если точное количество неизвестно или может меняться, вместо числа ставится звёздочка. Например, класс Teacher соотносится к классу AcademicSubject как 1..*, так как один учитель может преподавать множество учебных предметов. Агрегация и композиция являются частными случаями ассоциации.
- Агрегация (Agregation), это вид ассоциации, который используется для обозначения отношения “часть-целое” между классами. Он представляется стрелкой и незакрашенным ромбиком в сторону класса-целого. Для отношения агрегации “часть” может быть создана раньше, чем целое, и продолжать свой жизненный путь даже после уничтожения “целого”. Например: класс Library агрегирует класс Book как свою часть. Поле из списка книг в классе Library – это объекты другого класса (класса Book). В библиотеке множество книг. Если библиотека закроется, книги могут попасть в другое место: например, в класс BookShop.
- Композиция (Composition), представляется линией с закрашенным ромбиком на одном конце со стороны класса-целого. Это более строгий вид ассоциации, который указывает, что один класс является неотъемлемой частью другого. Например, если родительский класс уничтожается, то и его часть также уничтожается. Например: класс Flat содержит комнаты класса Room. Комнаты не могут существовать отдельно от квартиры.
- Обобщение, наследование, расширение (Inheritance), в самом деле, всё это одно и то же понятие, которое представляется линией с пустым (незакрашенным) наконечником-треугольником, указывающим на родительский класс. Один класс является другим, уточняя его. Например, класс MusicalInstrument является обобщением класса Guitar. Гитара является музыкальным инструментом (его уточнением).
- Реализация (Implementation), представлена пунктирной линией с пустым треугольником, указывающим на интерфейс. Эта связь по определению предполагает определение интерфейса и его реализацию в другом классе. К примеру, есть интерфейс IRepository (хранилище) и класс DataBase (база данных). Если класс “База данных” реализует интерфейс “Хранилище”, это означает, что он обеспечивает реализацию методов для хранения и извлечения данных, определенных в интерфейсе.
- Зависимость (Dependency), представляется пунктирной линией со стрелкой, идущей от класса-зависимости к классу, от которого он зависит. Это указывает, что изменения в зависимом классе могут повлиять на класс, от которого он зависит. Класс, отвечающий за расчёт налогов, в свою очередь зависит от класса “Налоговый сервис” для выполнения вычислений и налогообложения.
Чтобы закрепить теорию, приложим к уму пример UML-диаграммы классов с различными видами отношений – с наследованием, композицией, агрегацией и ассоциацией. Как правило, когда проектирование проводится ещё в более абстрактном режиме, классам могут не приписывать поля и методы, ограничиваясь названием. Это делается для того, чтобы акцентировать не внутренности классов, а их отношения между собой. Точно так же поступим и здесь.
Давайте “прочитаем” диаграмму. Как видно, есть веб-сайты WebSite, на которые заходят различные пользователи User. Причём на один сайт может заходить множество пользователей, а один пользователь может заходить на разные сайты. Об этом говорит ассоциация между ними с двумя звёздочками – связь “многие ко многим”. Вдобавок, пользователи могут быть двух типов: администраторы Admin и читатели Reader. Именно об этом сообщает связь “обобщение” между User и двумя классами: Admin и Reader.
Сайт WebSite содержит различные статьи Article. Более того, статьи не существуют вне сайта: они являются его неотъемлемой частью. Это можно понять по связи композиции между ними. И, наконец, каждая статья Article может содержать изображения Image. Причём изображения могут существовать и вне статьи: например, ждать своей участи в хранилище ресурсов сайта. При удалении статьи вмещённые в неё изображения не исчезают.
Вот такую информацию в итоге можно получить из этой UML-диаграммы. Это достаточно много. Особенно учитывая, что ни один класс не уточнён полями и методами – отражены только названия классов.
В итоге, UML-диаграммы классов обладают крайне высокой информативностью на квадратный сантиметр. Они позволяют разработчикам и командам проектов легко обмениваться идеями, чётко определяя иерархию классов. В результате, с помощью стрелок и блоков диаграммы классов UML позволяют выразить сложные концепции в лаконичной форме. Всем счастливого проектирования!