00 (1158679), страница 6
Текст из файла (страница 6)
Как уже говорилось, диаграммы деятельности интерпретируются в соответствии с формализмом сетей Петри. Начальная точка порождает один курсор управления (или маркер) для каждого исходящего перехода. Если для ребра определено событие, то курсор достигает конца ребра только после наступления такого события. Ограничивающее (сторожевое) условие также определяет, возможно ли перемещение курсора по ребру. При попадании курсора в узел действия происходит ожидание курсоров на всех входящих ребрах и лишь потом запускается единица работы. По завершении выполнения работы генерируются курсоры на всех исходящих ребрах. При попадании в узел разветвления (он имеет один вход и несколько выходов) курсор проходит дальше лишь по тому ребру, для которого выполнено сторожевое условие (вообще говоря, лучше когда оно одно, если несколько – произвольно выбирается единственное для передачи курсора). При попадании в узел объединения курсор из любого входа копируется на выходе (единственном). При попадании в узел разделения курсор дублируется на все выходы одновременно (происходит распараллеливание). Синхронизация обеспечивается узлом слияния, где происходит ожидание курсоров на всех входах и лишь затем выдается курсор на выходе. При попадании курсора в любой финальный узел вся деятельность, описываемая диаграммой, прекращается. Примерно по тем же правилам перемещаются курсоры объектов. Узлы действия могут иметь входные и выходные контакты для приема/выдачи курсоров объектов, изображаемые в виде квадратиков на границе узла. Если входных контактов несколько, действие в узле выполняется лишь тогда, когда на всех их пришли курсоры объектов.
Узлы разделения и объединения могут синхронизировать потоки управления с потоками объектов. Например:
Здесь прием возвращаемой позиции заказа на склад синхронизируется с изменением состояния объекта Item, который должен перейти в состояние returned (возвращен). Аналогично, возврат денег по возвращенному заказу синхронизируется со сменой состояния объекта Item на available (доступен). Обратите внимание, диаграмма с помощью вертикальных линий – «плавательных дорожек» разделяется на зоны ответственности (заказчик, продажи, бухгалтерия, склад).
Диаграммы деятельности следует использовать в следующих ситуациях:
-
при анализе потоков событий в конкретном варианте использования;
-
при анализе потоков событий во взаимодействующих вариантах использования.
Диаграммы компонентов моделируют физический уровень системы. На них изображаются компоненты ПО и связи между ними. На такой диаграмме обычно выделяют два типа компонентов: исполняемые компоненты и библиотеки кода. Каждый класс модели (или подсистема) преобразуется в компонент исходного кода. Между отдельными компонентами изображают зависимости, соответствующие зависимостям на этапе компиляции или выполнения программы. В модели системы может быть несколько диаграмм компонентов, в зависимости от числа подсистем или исполняемых файлов. Каждая подсистема является пакетом компонентов. Диаграммы компонентов применяются теми участниками проекта, кто отвечает за компиляцию и сборку системы.
Диаграмма размещения отражает физические взаимосвязи между программными и аппаратными компонентами системы. Она является хорошим средством для того, чтобы показать размещение объектов и компонентов в распределенной системе. Ее основные элементы:
• узел (node) – вычислительный ресурс – процессор (изображаемый с закрашенными боковыми гранями) или устройство (дисковая память, контроллеры различных устройств и т.д.);
• соединение (connection) – канал взаимодействия узлов.
Для узла можно задать выполняющиеся на нем процессы.
Диаграмма размещения используется менеджером проекта, пользователями, архитектором системы и эксплуатационным персоналом (системными инженерами), чтобы понять физическое размещение системы и распределение ее отдельных подсистем по вычислительным узлам.
При моделировании встроенных систем диаграмма размещения отображает связи микропроцессоров и устройств в составе системы.
Традиционный средства описания «линейных» языков (т. е. языков состоящих из цепочек символов) – БНФ, регулярные выражения, грамматики – плохо подходят для описания «плоского» языка, каковым является UML. Поэтому для описания UML применяется UML, таковое описание называется метамоделью. Ниже приведен фрагмент метамодели. Подробнее о ней можно узнать из стандарта.
Механизмы расширения UML предназначены для того, чтобы разработчики могли адаптировать язык моделирования к своим конкретным нуждам, не меняя при этом его основу (метамодель). Наличие механизмов расширения принципиально отличает UML от других средств моделирования и позволяет расширять его область применения. К механизмам расширения UML относятся: стереотипы; теги (именованные значения); примечания; ограничения.
Стереотип – это новый тип элемента модели, который определяется на основе уже существующего элемента. Стереотипы расширяют нотацию модели, могут применяться к любым элементам модели и представляются в виде текстовой метки или пиктограммы.
Стереотипы классов – это механизм, позволяющий разделять классы на категории. Например, основными стереотипами, используемыми в процессе анализа системы, являются: Boundary (граничный класс), Entity (класс-сущность) и Control (управляющий класс).
Помимо упомянутых стереотипов, разработчики ПО могут создавать свои собственные наборы стереотипов, формируя тем самым специализированные подмножества UML (например, для описания бизнес-процессов, Web-приложений, баз данных и т.д.). Такие подмножества (наборы стереотипов) в стандарте языка UML носят название профилей языка.
Теги (именованные значения) – специальные термины, используемые спецификации ограничений и свойств, такие как disjoint, complete, incomplete и др., могут сопровождаться указанием значения свойства, например, author=Вася или location=server.
Примечание – элемент диаграммы для комментария или другой текстовой информации. Примечание может содержать дополнительные сведения об элементах модели (с ними его соединяет пунктирная линия).
Ограничение – это семантическое ограничение, имеющее вид текстового выражения на естественном или формальном языке (OCL – Object Constraint Language), которое невозможно выразить с помощью нотации UML. Средства OCL не предназначены для описания процессов вычисления выражений, а только лишь фиксируют необходимость выполнения тех или иных условий применительно к отдельным компонентам моделей. Он может быть использован для решения следующих задач:
-
описание инвариантов классов и типов в модели классов;
-
описание пред- и постусловий в операциях и методах;
-
описание ограничивающих условий элементов модели;
-
навигация по структуре модели;
-
спецификация ограничений на операции.
Лекция 4. Объектный язык ограничений (OCL)
Ограничение (constraint) – это условие, накладываемое на значения одного или нескольких элементов модели. Ограничение не является инструкцией или командой, которую следует выполнить, оно формулируется как утверждение, которое должно быть истинным. Под элементом модели здесь имеется в виду объект, или класс, или пакет, или подсистема, или атрибут, или операция, или связь.
Р
ассмотрим пример:
Диаграмма содержит большое количество связей (ассоциаций и обобщений) необходимых для указания, что тип самолета должен соответствовать типу рейса, т. е. что пассажиров нельзя перевозить грузовым самолетом. О
граничение, записанное на естественном языке, неформально, его можно неправильно трактовать (например, что чартерные рейсы должны выполняться старыми самолетами, а регулярные – новыми). Поэтому имеет смысл использовать для записи формальный язык, который не допускает произвольных толкований и имеет стандартный синтаксис и семантику. Таковым является объектный язык ограничений OCL (Object Constraint Language
Слово implies означает логическую операцию импликации (a → b, читается так: из a следует b, это выражение ложно лишь при a – истина и b – ложь, в остальных случаях оно истинно). Вообще говоря, для записи ограничений можно использовать и другие формальные языки, например, языки программирования. Основное неудобство при этом – ограничение, записанное на языке программирования, похоже на часть программы, что придает ограничению посторонний смысл (может сложиться впечатление, что происходят какие-либо манипуляции над элементами модели, а это противоречит определению понятия ограничения).
Классификация ограничений:
-
Инвариант класса – условие, которое всегда справедливо для всех экземпляров класса (ключевое слово inv:).
-
Предусловие операции – условие, которое должно быть истинно перед выполнением операции (ключевое слово pre:).
-
Постусловие операции – условие, истинное всегда после выполнения операции (ключевое слово post:).
-
Тело запроса – описание результата операции-запроса, не модифицирующей объекты (ключевое слово body:)
-
Начальное значение атрибута или соединения (ключевое слово init:)
-
Правило вывода, описывающее производные атрибуты, связи или классы (ключевое слово derive:).
-
Определение (ключевое слово def:).
В примере мы описали инварианты класса Рейс.
Характеристики OCL:
-
текстовый (невизуальный) язык описания ограничений;
-
формальный язык, часть стандарта UML;
-
язык со строгой типизацией;
-
декларативный язык (для ограничений не определяется конкретная процедура их проверки);
-
платформо-независимый.
Никакое ограничение OCL не меняет состояния элементов модели (у него нет побочных эффектов), но с его помощью можно добавлять производные атрибуты и операции (используя def:).
Синтаксис OCL-выражения
<OCL-выражение> ::= <указание контекста> [(inv | pre | post | body | init | derive | def) : <тело выражения>]
В записи использованы символы языка БНФ: <> выделяют нетерминалы, ( | ) –вхождение одной из указанных альтернатив, [] вхождение 1 или более раз, {} – вхождение 0 или более раз. Терминалы записаны жирным шрифтом.
Контекст. В любом OCL-выражении указывается определенный контекст. Как правило, контекстом является элемент модели (пакет, класс, атрибут, операция), с которым связано ограничение.
<указание контекста> ::= context <имя элемента модели>
Для того чтобы сослаться на контекст в теле выражения используется слово self. Чтобы много раз не писать self, оно часто опускается. По смыслу self аналогично this в C++. В примере тип – сокращенная запись self.тип.
В теле выражения используются
-
выражения простых типов (boolean, integer, string, real);
-
элементы модели, для которой составлено ограничение;
-
коллекции.
Логический тип OCL почти таков как в языках программирования. Есть дополнительные операции xor и implies. Приоритет логических операций (кроме not) меньше арифметических и операций сравнения – так проще записывать сложные логические выражения. Целый и вещественный типы также стандартны. Имеются дополнительные операции a.max(b) и a.min(b), возвращающие максимум и минимум из двух чисел. Строки также похожи на строки языков программирования, только их нельзя сравнивать в лексикографическом порядке.
Примеры использования простых типов:
context Airline inv: name.toLower = ‘klm’ – здесь ‘klm’ – строка, toLower – стандартная операция над строкой, дающая как результат строку в нижнем регистре. Смысл ограничения: у любого экземпляра класса Airline значение атрибута name, записанное строчным буквами совпадает со строкой ‘klm’.
context Passenger inv: age >= ((9.6 - 3.5)* 3.1).floor implies mature = true – здесь floor – «округление вниз». Смысл ограничения: у любого экземпляра класса Passenger значения атрибутов age и mature таковы, что если age > 18, то mature = true.
Ограничения могут быть указаны на диаграмме в примечании, якорь примечания в таком случае играет роль указателя на контекст
В OCL употребляются условные выражения:
<условное выражение> ::=
if <логическое выражение> then <выражение>
else <выражение>
endif
Пример: if (x >= 0) then x else – x endif возвращает модуль x или x.abs().