Главная страница

Лабораторная работа №1. UML. Практикум по промышленному


Скачать 1.02 Mb.
НазваниеПрактикум по промышленному
АнкорLab1_UML
Дата19.02.2023
Размер1.02 Mb.
Формат файлаdocx
Имя файлаЛабораторная работа №1. UML.docx
ТипПрактикум
#944949
страница8 из 8
1   2   3   4   5   6   7   8

Пример создания UML-диаграмм архитектуры проекта с помощью PlantUML


Задание: разработать эскиз проекта системы управления книгами в библиотеке. При выполнении задания ограничимся диаграммами классов и последовательности.

Создадим новый проект. В меню необходимо выбрать File>New Project. В диалоге выбора шаблона проекта, не нужно выбирать никакого шаблона (т.е. проект будет пустой, но с одним одноименным модулем). Название проекта ­ UMLLab. Если появится запрос на замену текущего проекта создаваемым, то лучше разрешить замену, так как старый проект уже не нужен.



После открытия проекта разверните содержимое модуля UMLLab с помощью серого треугольника. Папка .idea и файл UMLLab.iml хранят в себе все настройки проекта и модуля. Папка src будет включать в себя исходные коды .java программы.



Создание диаграммы классов


Откройте контекстное меню модуля и выберите создание новой UML­диаграммы классов.

В качестве имени файла можно ввести LibraryClassDiagram. В итоге среда разработки примет следующий вид.



В центре показан “код” диаграммы, которая загружается в качестве примера каждый раз при создании новой диаграммы классов. Слева показана уже нарисованная диаграмма. При редактировании кода диаграмма сразу же изменяется.

Код диаграммы начинается строчкой @startumlи заканчивается @enduml. Между ними описываются сущности (классы, интерфейсы, перечисления и т. д.), а также связи между сущностями. Как именно это делать, будет пояснено ниже, но полнуюинформациюможнопосмотретьвфайле PlantUML_Language_Reference_Guideили по адресу http://plantuml.sourceforge.net/classes.html.

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

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

@startuml class Book {

}

class Library {

}

@enduml




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

У класса Book должны быть атрибуты: международный стандартный книжный номер (ISBN), название, автор, номер книги в библиотеке, год издания, а также операции, устанавливающие и получающие данные атрибуты. Однако по причине их многочисленности и общеупотребительности, эти операции не будут включаться в диаграмму классов. Помимо них, у класса Book нет других операций.

В классе Library должны быть атрибуты: количество книг и название библиотеки. Операции: найти нужную книгу по какому­либо параметру, например, по ISBN, добавить новую книгу в библиотеку, удалить необходимую книгу.

@startuml

skinparam classAttributeIconSize 0 class Book {

­ISBN : String

­author : String [1..*]

­numberInLibrary : long

­year : int

}

class Library {

­numberOfBooks : long

­name : String

+findBookByISBN(ISBN : String) : Book

+addNewBook(book : Book) : boolean

+deleteBook(number : long) : boolean

}

@enduml




Строка “skinparam classAttributeIconSize 0” отключает изображение метки видимости в виде картинки. Это нужно потому, что символы меток видимости стандартизированы, а картинки ­ нет, поэтому лучше использовать символы, если нет соглашений об иных обозначениях меток видимости.

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

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

Book "0..*" <­­> "1" Library




На диаграмме сразу отобразились все изменения, классы были перекомпонованы. Данная ассоциация может быть прочитана как “в библиотеке может быть от нуля до бесконечности книг, а у книги может быть только одна библиотека которой она находится)”.

Продолжим конкретизировать эскиз. В библиотеке могут находиться также не только обычные книги, но и, к примеру, журналы. Самым очевидным решением было бы сделать класс Magazine подклассом класса Book. Но у журналов нет ISBN и конкретного автора! К тому же для большинства журналов для обозначения даты издания только года недостаточно. Соответственно, архитектурным решением может быть сделать общий абстрактный класс AbstractBook, в котором будут реализованы общие операции для всех сущностей, что находятся в библиотеке. От него будут наследоваться классы Book и Magazine. Но нельзя создать никаких экземпляров класса AbstractBook, а нам необходимо именно ими управлять в классе Library. Это решение не подходит, либо должно быть усовершенствовано.

Далее, для того, чтобы сделать возможным управление классами­наследниками AbstractBook, можно вынести методы из AbstractBook в интерфейс LibraryEntity. Абстрактный класс будет реализовывать этот интерфейс. Таким образом, Library сможет управлять объектами типа LibraryEntity. Например, станет возможным такой код.

LibraryEntity entity = new Book();

Почему такое возможно? Потому что абстрактный класс AbstractBook реализует интерфейс LibraryEntity, а класс Book наследует абстрактный класс AbstractBook. Язык Java позволяет присваивать интерфейсу ссылки на объекты тех классов, которые реализуют этот интерфейс.

Это решение и является подходящим для такой ситуации.

Соответственно, будут изменения и в классе Library, изменятся названия атрибутов, добавятся новые операции и изменятся старые. Дополнительно изменено имя свойства “numberInLibrary” на “ID”.

Если бы не было этапа проектирования, который сейчас и выполняется, то именно сейчас пришлось бы переписывать огромное количество кода. Именно поэтому принцип “сначала спроектируй ­

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

Внесем все эти изменения в UML­код.

@startuml

skinparam classAttributeIconSize 0
interface LibraryEntity {

+getID() : long

+getName() : String

}
abstract class AbstractBook {

­ID : long

­name : String

}
class Book {

­ISBN : String

­author : String [1..*]

­year : int

}
class Magazine {

­datePublication: LocalDate

­publisher : String

}
class Library {

­numberOfEntities : long

­name : String

+findEntityByName(name : String) : LibraryEntity

+findEntityByID(id : long) : LibraryEntity

+addNewEntity(entity : LibraryEntity) : boolean

+deleteEntity(id : long) : boolean

}
LibraryEntity "0..*" <­­> "1" Library
LibraryEntity <|.. AbstractBook AbstractBook <|­­ Book AbstractBook <|­­ Magazine @enduml


Добавим комментарий к классу Magazine.

class Magazine {

­datePublication: LocalDate

­publisher : String

}

note right: LocalDate is from DateTime API in Java 8




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

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

Создание диаграммы последовательностей


Создадим в этом же проекте (модуле) файл диаграммы последовательностей.

Имя диаграммы: LibrarySequenceDiagram. Так как это диаграмма последовательности, то с помощью её мы сможем показать, какова же последовательность действий в проектируемой системе. Иначе говоря, что же будет делать система при наступлении той или иной ситуации?

Разработаем две диаграммы последовательности: одну для сценария нахождения чего­либо в библиотеке по его имени (name), вторую для сценария удаления чего­либо из библиотеки по идентификатору (ID).

ПолнуюинформациюоспецификацииPlantUMLдлядиаграммпоследовательностейможнопосмотреть в файле PlantUML_Language_Reference_Guide или по адресу http://plantuml.sourceforge.net/sequence.html.

Сценарийнахождениячего-либовбиблиотекепоимени

Сначала необходимо определить объекты, которые посылают друг другу сообщение (иначе говоря, вызывают или каким­либо образом используют друг друга). Когда в классе Library вызывается функция findEntityByName(), то эта функция будет брать список всех сущностей LibraryEntityList, хранящихся в библиотеке, и выполнять в нем поиск. Почему этот список сущностей не был указан в атрибутах в диаграмме классов? Потому что этот список там представлен в виде двусторонней ассоциации. Поэтому имя этого списка будет в диаграмме последовательности, но не будет в диаграмме классов.

Функция findEntityByName() будет вызываться классом­клиентом библиотеки LibraryClient, которого также не было на диаграмме классов. Таким образом, можно написать следующий код, отображающийся в UML.

@startuml

LibraryClient ­> Library : findEntityByName(name : String) Library ­> LibraryEntityList : getEntity

LibraryEntityList ­> Library: anEntity @enduml



В диаграмме происходит следующее: LibraryClient вызывает у Library метод findEntityByName, Library запрашивает у списка LibraryEntityList одну сущность, и эта сущность передается библиотеке.

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

@startuml

LibraryClient ­> Library : findEntityByName(name : String) loop all entities in list

Library ­> LibraryEntityList : getEntity LibraryEntityList ­> Library : anEntity alt anEntity.name == name

Library ­> LibraryClient : anEntity

end end @enduml



Однако по такой диаграмме последовательности становится понятно, что в LibraryClient будут “возвращаться” много элементов библиотеки, если они будут подходить под поисковый запрос. Значит, необходимо возвращать результаты запроса не отдельными элементами (классу­клиенту обрабатывать большое количество результатов неудобно), а отдельным классом ResultEntityList. Значит, каждый раз, когда полученный из списка anEntity будет удовлетворять запросу, он будет отправляться в ResultEntityList, а по завершении цикла, список результатов ResultEntityList будет возвращен клиенту LibraryClient.

@startuml

LibraryClient ­> Library : findEntityByName(name : String) loop all entities in list

Library ­> LibraryEntityList : getEntity LibraryEntityList ­> Library : anEntity alt anEntity.name == name

Library ­> ResultEntityList : anEntity

end end

ResultEntityList ­> LibraryClient : resultList @enduml

Сценарийудалениячего-либоизбиблиотекипоидентификатору

Клиент библиотеки посылает библиотеке запрос на удаление элемента из библиотеки. Класс библиотеки просматривает весь список своих элементов и ищет такой элемент, ID которого совпадает с запрашиваемым. Если такой элемент находится (используется фрейм alt), то из списка этот элемент удаляется, а клиенту возвращается значение true (элемент на самом деле удален). Если же в списке не было найдено никакого подходящего элемента, то никакого элемента не было удалено, и клиенту возвращается значение false.

@startuml

LibraryClient ­> Library : deleteEntity(id : long) loop all elements in list

Library ­> LibraryEntityList : getEntity LibraryEntityList ­> Library : anEntity alt anEntity.id == id

Library ­> LibraryEntityList : deleteFromList(entity : LibraryEntity) Library ­> LibraryClient : true

end

end

Library ­> LibraryClient : false @enduml



Коррекция диаграммы классов


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

Изменились возвращаемые значения в операциях поиска в классе Library.

@startuml

skinparam classAttributeIconSize 0
interface LibraryEntity {

+getID() : long

+getName() : String

}
abstract class AbstractBook {

­ID : long

­name : String

}
class Book {

­ISBN : String

­author : String [1..*]

­year : int

}
class Magazine {

­datePublication: LocalDate

­publisher : String

}

note right: LocalDate is from DateTime API in Java 8
class Library {

­numberOfEntities : long

­name : String

+findEntityByName(name : String) : ResultEntityList

+findEntityByID(id : long) : ResultEntityList

+addNewEntity(entity : LibraryEntity) : boolean

+deleteEntity(id : long) : boolean

}
class LibraryClient
LibraryEntity "0..*" <­­> "1" Library
LibraryEntity <|.. AbstractBook AbstractBook <|­­ Book AbstractBook <|­­ Magazine
LibraryClient ..> Library @enduml


Задания для самостоятельной работы


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

Вариант №1, 16


Проект “Управление магазином сладостей”.

Вариант №2, 17


Проект “Расписание железнодорожной станции”.

Вариант №3, 18


Проект “Рисование геометрических фигур”.

Вариант №4, 19


Проект “Редактирование видеофайлов”.

Вариант №5, 20


Проект “Электронная зачетная книжка”.

Вариант №6, 21


Проект “Хранитель паролей”.

Вариант №7, 22


Проект “Расчет скидок” для магазина электронной техники.

Вариант №8, 23


Проект “Управление установленными приложениями”.

Вариант №9, 24


Проект “Модель Солнечной системы”.

Вариант №10, 25


Проект “Магазин электронных книг”.

Вариант №11, 26


Проект “Расписание школьных уроков”.

Вариант №12, 27


Проект “Электронный школьный дневник”.

Вариант №13, 28


Проект “Текстовый редактор”.

Вариант №14, 29


Проект “Справочник болезней”.

Вариант №15, 30


Проект “Управление закладками”.

Литература, ссылки


  1. Фаулер M. UML. Основы, издание. Пер. с англ. СПб: СимволПлюс, 2004. 192 с., ил.

  2. Иванов Д. Ю., Новиков Ф. А. Основы моделирования на UML: Учеб. пособие. СПб.: Изд­во Политехн. ун­та, 2010. 249с.

  3. https://ru.wikipedia.org/wiki/UML

  4. https://ru.wikipedia.org/wiki/%C4%E8%E0%E3%F0%E0%EC%EC%E0_%EA%EB%E0%F1%F1% EE%E2

  5. https://ru.wikipedia.org/wiki/IntelliJ_IDEA

  6. http://blog.gelin.ru/2014/02/plantuml.html

  7. http://plantuml.sourceforge.net/PlantUML_Language_Reference_Guide.pdf


­­


1   2   3   4   5   6   7   8


написать администратору сайта