Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Методы и средства проектирования информационных систем и технологий. Основы UML. Учебное пособие.pdf

Рис. 2.5. Выборочные перечисления
В примечании, прикрепленном к Visibility Kind, указаны стандартные символы, используемые в UML для определения видимости функции.
Индикатор VisibilityKind является примером обзначения для атрибутов или
операций.
В спецификации UML все имена типов перечисления заканчиваются на
«Kind», как показано на Visibility Kind (рис. 2.5). На рисунке 2.6 показано, что
мы включили как Traffic Li ght Color Kind, так и Traffic Light Colour Kind для
поддержки сигналов трафика как в США, так и в Великобритании. Перечисленные литералы имеют идентичность только внутри перечисления. Если вы
попытались проверить на равенство между значениями зелёного светофора, вы
можете или не можете заставить их отображаться как равные, или вы можете
просто получить ошибку типа. Если вы хотите ссылаться на каждый цвет независимо, используйте оператор области именования ".".
Перечисленные литералы неизменны. Мы не можем изменить значение
любого из литералов, поэтому они не могут появляться в левой части оператора
присваивания или как возвращаемое или выходное значение операции. Тем не
менее, они могут использоваться для установки значения атрибута или переменной или проверяться на равенство/равенство.
31

Рис. 2.6. Унаследованные перечисления
Мы не рассматриваем внутреннее представление перечислений. Это могут
быть строки, целые числа, начинающиеся с единицы, целые числа, начинающиеся с нуля, или что-то еще. Некоторые инструменты могут позволять указывать значения или порядок литералов для генерации кода, но это не является
частью текущего UML.
Использование только этих нескольких примитивных типов и перечислений очень ограничено. UML предлагает возможность создавать дополнительные типы на основе примитивов. Они выглядят как классы, за исключением того, что они используют ключевое слово «dataType». На рисунке 2.7 показано
два сконструированных типа данных. Мы также использовали «+», публичную
видимость, чтобы указать, что свойства и операции dataType видны вне
dataType.
Также были добавлены некоторые операции к типу даты datatType, чтобы
поддержать добавление дней к текущей дате и сравнение дат. Результат первой
операции addToDate (days: Integer) не нуждаётся в возвращаемом значении, потому что эта операция обновляет значение DateType.
На рисунке 2.7 ограничения помещены на ту же строку, что и свойство с
ограничениями. Также, в случае, когда в блоке не хватает места их можно разместить в отдельном блоке, который называется «ограничения». Справа и на
рис. 2.8 использован формальный формат:
Во всех случаях ограничения заключены в фигурные скобки.
32

Рис. 2.7. Два пользовательских типа данных
Рис. 2.8. Блок «ограничения»
Хороший тип (data Type или class) поддерживает абстракции. В этом контексте абстракция представляет собой единую концепцию, которая освобождена от физических деталей или деталей реализации, а использование сокрытия
информации скрывает эти детали, чтобы предотвратить злоупотребление или
раскрытие деталей. Сокрытие деталей с помощью таких методов, как инкапсуляция, будет способствовать переносимости.
Например, если бы мы создали класс Stack, возможно, реализованный с
помощью списка, мы бы не хотели, чтобы пользователь мог дополнительно устанавливать или получать какие-либо элементы списка, кроме установленных
разработчиком (рис. 2.9).
33

Рис. 2.9. Класс Stack
Некоторые разработчики моделей стереотипируют data Type как Abstract
DataType (или ADT). Это не является частью стандарта, но это полезно.
«Abstract Data Type» объявляет, что вы предоставили или запретили все необ-
ходимые операции для поддержания согласованности типа. ADT имеет в виду
некоторые математические или архитектурные абстракции.
В подходе к реализации класса Stack, список скрыт от внешней стороны, и
определены только «безопасные» операции.
Атрибут или операцию можно отметить определённым модификатором,
который изменяет некоторую, обычно незначительную, интерпретацию компонента.
На рисунке 2.10 изображён класс Member, который использует данные типа Full Name и Date.
Каждый экземпляр Member имеет атрибут name. Если необходим сослаться на first Name текущего участника, это будет current Member.name. first Name.
Если требуется указать год, в котором родился текущий участник, это будет
current Member.birthdate.year.
Рис. 2.10. Класс, использующий пользовательские data Types
34

Существует ещё один атрибут для Member, hasAdultPrivileges типа
Boolean. Если вы посмотрите внимательно, вы увидите, что перед именем атри-
бута стоит косая черта. Это имеет особое значение в UML, оно указывает, что
значение атрибута является производным. Значение производного атрибута
может быть вычислено по необходимости на основе других атрибутов или доступных свойств.
Во многих библиотеках материал делится по возрастным категориям. Мы
устанавливаем видимость для name, hasAdultPrivileges и isAdult () как public (+),
что означает, что любой может просматривать значения этих атрибутов или вызывать операцию. Мы сохранили дату рождения как конфиденциальную, поскольку она, вероятно, будет идентифицирующей личность информацией, т.е. в
соответствии с законодательством должна быть защищена от разглашения. Несмотря на то, что дата рождения является частной (–), она доступна в операции
isAdult (), поэтому она может вычислить значение свойства hasAdultPrivileges.
До того, как экземпляр Member собирается заимствовать книгу с ограничением по возрасту, должна быть вызвана операция isAdult (). Результат будет
присвоен has Adult Privileges. Как только экземпляр Member объявлен как соответствующий возрасту, операцию isAdult () больше вызывать не требуется. Булевыми свойствами или операциями принято называть форму has Property или
isInState, чтобы использование значений True или False было естественно.
Также для свойства возможно назначить значение по умолчанию. На рисунке 2.11 мы модифицируем логический флаг hasAdultPrivleges, чтобы иметь
значение по умолчанию False. Это означает, что всякий раз, когда мы создаем
новый экземпляр Member, флагу будет присваиваться начальное значение False.
Рис. 2.11. Иллюстрация значения по умолчанию (начального значения) и readOnly
35

В этом случае всякий раз, когда читатель пытается взять книгу для взрослых, мы проверяем значение флага. Если поле имеет значение False, мы бы вызвали операцию isAdult (). Если читатель является взрослым, тогда мы устанавливаем флаг, чтобы в следующий раз, когда читатель попытается взять книгу
для взрослых, мы увидим, что читатель уже имеет разрешение.
Значение по умолчанию должно быть того же типа, что и базовый атрибут.
Обратите внимание, что хотя поле даты рождения помечено как частное
(–), это значение доступно внутри для операций над элементом. Следовательно,
операция isAdult () может прочитать поле даты рождения.
Также возможно присвоить значение по умолчанию аргументам операции.
На рисунке 2.12 мы предоставляем логическое значение по умолчанию, используя логический литерал False для аргумента isRenew. Нам нужно изменить аргумент a только одновременно с обновлением книги.
Есть моменты, когда мы хотим, чтобы область была защищена от изменений. Мы можем сделать свойство частным, что исключит только те изменения,
которые происходят вне экземпляра. Если требуется большая защита, можно
добавить к этому свойству {readOnly}. Это указывает на то, что свойство должно быть защищено от всех изменений после его инициализации. На рисунке
2.11 мы пометили дату рождения участников как {readOnly}.
На практике это может быть слишком строго. Нередко нужно исправлять некоторые поля в случае случайных или намеренных ошибок ввода.
В большинстве инструментов readOnly не поддерживается сгенерированным кодом, поэтому рекомендуется сделать свойство закрытым.
Как и во многих свойствах, имя свойства является сокращенной формой
для isReadOnly = True. Значение по умолчанию для isReadOnly – False.
36
Рис. 2.12. Пример аргумента с присвоением значения по умолчанию

{query} – это операция, которой не разрешено изменять какие-либо значения атрибутов экземпляра. Пометка операции как query, также как и пометка
атрибута readOnly, указывает на то, что единственное, что изменяется после
операции, это возвращаемое значение.
Это, как и isReadOnly, является возможностью моделирования и не всегда
обеспечивается сгенерированным кодом (рис. 2.13) для использования {query}.
Использование {query} на рисунке указывает на то, что операция isAdult ()
не изменит какой-либо атрибут элемента или что-либо еще, кроме возврата логического значения. Запрос – это свойство операции, которое отображается как
обозначение {query}.
Параметры для операции могут быть помечены их предполагаемым направлением. Существует четыре возможных значения перечисления для направления параметров. Значение по умолчанию, используемое для
ParameterDirectionKind, если не указано иное, – «in». Крайний правый столбец в
таблице указывает, когда значения параметра заслуживают доверия, для параметра «in» или «inout» должны быть заданы значения, прежде чем они будут
переданы в поведение / операцию. Параметры, отмеченные как «out», «inout»
или «return», будут иметь новые значения после вызова, и любое ранее установленное значение будет потеряно во время вызова.
На рисунке 2.14 первые два параметра – «в». Следующий параметр, Дебет,
представляет стоимость предстоящей поездки, однако, в зависимости от остатка на кредитной карте, он может быть только частично финансируемым (требу-
Рис. 2.13. Операция {query}
37

Рис. 2.14. Пример работы с использованием Parameter Direction Kind
ется дополнительный источник финансирования). В этом случае приложение
оставляет остаток в параметре дебетования, и success Flag будет установлен в
значение false. Поэтому мы устанавливаем их флаги направления на «inout» и
«out» соответственно. Мы резервируем Return Type для более серьезных сбоев,
таких как не обнаружение кредитной карты, ввод-вывод или сетевые ошибки.
Подходы, которые вызывают исключения, также возможны, но здесь не рассматриваются.
Обычная практика – упорядочивать параметры по их направлению (используя порядок «in», «inout», «out» и «return»). Поскольку «in» является значением по умолчанию, оно часто опускается. Также обычно опускается направление вида «return», потому его обычно можно узнать по месту в конце вызова
операции.
Когда мы назначаем значение по умолчанию (начальное) атрибуту класса
или значение слоту в экземпляре, мы можем использовать значение Literal. Мы
уже использовали многие из них раньше. Например, на рис. 3.16 мы использовали целочисленные литералы для установки значения для полей даты. На рисунке 2.15 мы использовали строковый литерал для присвоения значения полю
заголовка.
38
Рис. 2.15. Класс и экземпляр

Рассмотрим обозначение, возможности и особенности спецификации объекта/экземпляра.
Давайте сначала различим объекты, экземпляры и характеристики экземпляров. «Объект» – это либо элемент реального мира (M1), либо элемент кода/
реализации (M0). «Экземпляр» – это то же самое, с упором на тот факт, что
здесь задействован класс или тип (классификатор), т.е. «экземпляр» класса.
На рисунке 2.15 мы видим спецификацию экземпляра с именем myBook,
которая представляет экземпляр класса Book, который в настоящее время называется myBook, у которого есть слот заголовка, содержащий «Tom Sawyer».
Спецификация экземпляра – это элемент модели (обычно с соответствующими
элементами диаграммы), который обычно обозначает экземпляр, но может обозначать один из набора экземпляров. Например, если существует много книг с
названием «Tom Sawyer», Спецификация экземпляра может относиться к любому из совместимых экземпляров.
Можно подумать, что спецификация экземпляра похожа на класс. Однако
класс обозначает набор экземпляров, а спецификация экземпляра определяет
один из потенциально меньшего набора. В UML 2.5 спецификация экземпляра
представляет собой прямоугольную рамку с отсеком для имени и дополнительным отсеком для слота. Раздел имени включает подчеркнутое имя, в приведённом выше случае это myBook, за которым следует ":", а затем имя класса, экземпляром которого являются экземпляры, в данном случае Book.
Все поля, кроме ":", необязательны. Если вы не указываете класс, спецификация экземпляра указывает, что класс не важен, и подойдет экземпляр любого класса. Если вы не укажете имя, то имя экземпляра не имеет значения.
Раздел имени также может отображать любые соответствующие стереотипы.
Под отделением имени находятся слоты. Они представляют атрибуты из
класса с необязательными буквальными значениями, которые являются значениями для этих атрибутов в текущий момент. Литеральное значение должно
39

быть совместимо с типами атрибутов. Часто типы атрибутов повторяются после
имени слота, как показано ниже:
title: String = «Tom Sawyer»
Можно добавить дополнительный блок ограничений, чтобы фиксировать
любые ограничения в этом экземпляре. Нет отсеков операций и сигналов. Элементы, которые будут в этих отсеках, будут отражены в определении класса,
и их не нужно будет повторять. Точно так же в отсеке для слотов не повторяйте
слоты, если вы действительно не заботитесь об их значениях в данном случае.
Дополнительный блок ограничений может быть добавлен для захвата любых ограничений в этом случае. Там нет операций или сигналов отсеков. Элементы, которые будут находиться в этих отсеках, будут включены в определение класса и не должны повторяться. Точно так же, в разделе слотов, не повторяйте слоты, если вы действительно не заботитесь об их значениях в этом
случае.
Следует различать имя экземпляра и значение любого конкретного атрибута. Например, мы могли бы изменить определение класса, чтобы оно имело атрибут name: String, и соответственно изменить слот заголовка на слот имени.
В таком случае имя экземпляра по-прежнему будет «myBook», а атрибут имени
экземпляра – «TomSawyer».
В приведённом ниже примере (рис. 2.16), мы показываем myBDate как экземпляр даты dataType. Как и в случае с классами, мы не показываем никаких
операций, а просто дублируем определения типа. Пунктирная стрелка, которую
мы используем для соединения двух элементов (рис. 2.15, 2.16), – это необязательная стрелка зависимости, указывающая, что экземпляры зависят от определения их класса или типа.
Можно использовать литерал или косвенный литерал через спецификацию
экземпляра, чтобы присвоить значение свойству или слоту, как мы видели,
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
