UML2 и унифицированный процесс. Джим арлоуайла нейштадтпрактический объектно ориентированныйанализ и проектированиеu
Скачать 6.08 Mb.
|
12.9.3. Документирование диаграмм последовательностей Одно из замечательных свойств диаграмм последовательностей – воз можность добавлять в них «сценарии» путем размещения примечаний в нижней левой части диаграмм (рис. 12.8). Это делает диаграмму на много более понятной заинтересованным лицам, которые не являются специалистами в UML, например пользователям или экспертам. Сце нарий может состоять из фактических шагов прецедента или краткого обзора того, что происходит на диаграмме, представленного в тексто вой форме. В любом случае сценарий может быть полезным дополне нием, особенно если диаграмма сложна. 12.9.4. Инварианты состояния и ограничения Сообщение, получаемое экземпляром, может обусловить изменение его состояния. 280 Глава 12. Реализация прецедентов Состояние определяется как «условие или ситуация в ходе жизни объ екта, в течение которой он удовлетворяет некоторому условию, осуще ствляет некоторую деятельность или ожидает некоторое событие» [Rumbaugh 1]. У каждого классификатора может быть автомат, опи сывающий жизненный цикл его экземпляров с точки зрения состоя ний, в которых они могут находиться, и событий, которые обуславли вают переходы между этими состояниями. Не все сообщения приводят к изменению состояния. Например, сооб щение, которое возвращает значение некоторого атрибута и не имеет никаких побочных действий, никогда не генерирует изменения со стояния. Состояние экземпляров на линиях жизни объектов можно показать с помощью инвариантов состояния (state invariants). Добавление инвариантов состояния на диаграмму последовательно стей может быть весьма полезным методом анализа, поскольку позво ляет фиксировать ключевые состояния жизненного цикла линии жиз ни. Они отражают важные состояния системы и могут быть основой для автоматов, обсуждаемых в главе 21. Рассмотрим конкретный пример. На рис. 12.11 показан прецедент из простой системы обработки заказов, имеющей следующие ограничения: • заказ должен полностью оплачиваться единовременным платежом; • позиции, указанные в заказе, могут поставляться только после оплаты; Основной поток: 1. Прецедент начинается, когда актер Customer создает новый заказ. 2. Customer полностью оплачивает заказ. 3. Товары доставляются Customer в течение 28 дней после даты окончательного платежа. Прецедент: ProcessAnOrder Предусловия: Нет. Краткое описание: Покупатель делает заказ, который затем оплачивается и доставляется. Постусловия: 1. Заказ оплачен. 2. Товары доставлены в течение 28 дней после окончательного платежа. Альтернативные потоки: ExcessPayment OrderCancelled GoodsNotDelivered GoodsDeliveredLate PartialPayment ID: 5 Главные актеры: Customer Второстепенные актеры: Нет. Рис. 12.11. Спецификация прецедента ProcessAnOrder 12.9. Диаграммы последовательностей 281 • позиции доставляются покупателю в течение 28 дней после оплаты. В реальности процесс обработки заказов обычно намного более слож ный и гибкий по сравнению с рассматриваемым примером. Тем не менее пример служит иллюстрацией инвариантов состояний. На рис. 12.12 показана диаграмма последовательностей для ProcessAnOrder (обработка заказа). Мы видим, что сразу после создания экземпляр Order переходит в со стояние unpaid (не оплачено) (изображается в виде прямоугольника со скругленными углами). Это сообщает о том, что все вновь создаваемые экземпляры Order находятся в состоянии unpaid. При получении сообще ния acceptPayment() (принять платеж), которое должно обозначать пол ную оплату, экземпляр переходит в состояние paid (оплачено). После этого экземпляр DeliveryManager (менеджер по доставке) посылает сооб щение deliver() (доставить). Он передает это сообщение экземпляру Order, что приводит к его переходу в состояние delivered (доставлено). Если класс Order также имеет автомат, его состояния должны соответ ствовать всем инвариантам состояний, присутствующим на его диа граммах последовательностей. Рисунок 12.12 иллюстрирует применение ограничений. Они записы ваются в фигурных скобках и размещаются на (или рядом) линиях жизни. Ограничение, обозначенное на линии жизни, указывает на что то, что должно быть истинным для экземпляров, начиная с этого момента и далее. Ограничения часто формулируются на естественном языке, хотя в UML есть формальный язык ограничений (OCL), кото рый обсуждается в главе 25. На рисунке показано ограничение продолжительности. Линия жизни объекта :Customer имеет две метки, A и B, и ограничение {B – A <= 28 days}. :Customer :Order :DeliveryManager :OrderManager «create» raiseOrder() acceptPayment() acceptPayment() deliver() deliver() инвариант состояния A B {B – A <= 28 days} метка sd ProcessAnOrder ограничение unpaid paid delivered Рис. 12.12. Диаграмма последовательностей прецедента ProcessAnOrder 282 Глава 12. Реализация прецедентов Это говорит о том, что промежуток времени между точками A и B не должен превышать 28 дней. Точка A обозначает момент оплаты, а точ ка B – момент доставки товаров покупателю. На естественном языке это ограничение означает, что «заказ должен быть доставлен в течение 28 дней после получения платежа». На линию жизни может быть помещен любой тип ограничения. Широ ко распространены ограничения значений атрибутов экземпляров. И наконец, обратите внимание, что на рис. 12.12 не использовались ни активации, ни возвраты сообщений. Это объясняется тем, что основ ное внимание данной диаграммы направлено на сроки и инварианты состояний, и упомянутые характеристики не добавили бы сюда ника кой полезной информации. 12.10. Комбинированные фрагменты и операторы Диаграммы последовательностей можно разделить на области, называе мые комбинированными фрагментами (combined fragments). Рис. 12.13 иллюстрирует довольно богатый синтаксис комбинированного фраг мента. Комбинированные фрагменты разделяют диаграмму последовательно стей на области с различным поведением. У каждого комбинированного фрагмента есть один оператор (operator), один или более операндов (operands) и нуль или более сторожевых условий (guard conditions). Оператор определяет, как исполняются его операнды. Оператор определяет, как исполняются его операнды. [сторожевоеУсловие2] b( ) c( ) любые сторожевые условия должны размещаться над первым сообщением операнда :A :B :C операнд a( ) комбинированный фрагмент операнд sd OperatorSyntax имя оператор [сторожевоеУсловие1] Рис. 12.13. Синтаксис комбинированного фрагмента 12.10. Комбинированные фрагменты и операторы 283 Сторожевые условия определяют, будут ли исполняться эти операн ды. Сторожевое условие – это логическое выражение, и операнд испол няется тогда и только тогда, когда это выражение истинно. Одно сторо жевое условие может применяться ко всем операндам или каждый опе ранд может иметь собственное уникальное сторожевое условие. Сторожевые условия определяют, будут ли выполняться данные опе ранды. Полный список операторов приведен в табл. 12.3. Таблица 12.3 Оператор Полное имя Семантика Раздел opt option Единственный операнд выполняется, если условие истинно (как if … then). 12.10.1 alt alternatives Выполняется тот операнд, условие которого истинно. Вместо логического выражения может использоваться ключевое слово else (как select … case). 12.10.1 loop loop Имеет специальный синтаксис: loop min, max [condition] повторять минимальное количество раз, за тем, пока условие истинно, повторять еще ( max – min) число раз. 12.10.2 break break Если сторожевое условие истинно, выполня ется операнд, а не все остальное взаимодей ствие, в которое он входит. 12.10.2 ref reference Комбинированный фрагмент ссылается на другое взаимодействие. 13.2 par parallel Все операнды выполняются параллельно. 20.5.2 critical critical Операнд выполняется автоматически без прерывания. 20.5.2 seq weak sequencing Все операнды выполняются параллельно при условии выполнения следующего огра ничения: последовательность поступления событий на одну линию жизни от разных операндов такая же, как и последователь ность операндов. В результате наблюдается слабая форма упорядочения; отсюда название (weak se quencing – слабое упорядочение). 12.10 strict strict sequencing Операнды выполняются в строгой последо вательности. 12.10 284 Глава 12. Реализация прецедентов Таблица 12.3 (продолжение) Самые важные из них: opt, alt, loop, break, ref, par и critical. Операторы opt, alt, loop и break подробно обсуждаются в следующих подразделах, а ref – в следующей главе. Операторы par и critical имеют отношение к параллелизму, что является вопросом проектирования. Они обсуж даются в разделе 20.5 при рассмотрении параллелизма. Остальные операторы используются редко. В таблице предоставлен достаточный объем информации для их применения в случае необходимости. 12.10.1. Ветвление с помощью операторов opt и alt Рисунок 12.14 иллюстрирует синтаксис операторов opt и alt. opt создает единственную ветвь. Оператор Полное имя Семантика Раздел neg negative Операнд демонстрирует неверные взаимо действия. Применяется, когда необходимо показать, что не должно произойти. 12.10 ignore ignore Перечисляет сообщения, которые намеренно исключены из взаимодействия. Разделен ный запятыми список имен проигнорирован ных сообщений в фигурных скобках помеща ется после имени оператора, например {m1, m2, m3}. Например, взаимодействие может представ лять тестовый пример, в котором принято ре шение игнорировать некоторые сообщения. 12.10 consider consider Перечисляет сообщения, намеренно вклю ченные во взаимодействие. Разделенный за пятыми список имен сообщений в фигурных скобках помещается после имени оператора. Например, взаимодействие может представ лять тестовый пример, в который решено включить подмножество возможных сообще ний. 12.10 assert assertion Операнд является единственно возможным допустимым поведением в данный момент взаимодействия, любое другое поведение бы ло бы ошибочным. Используется как средство обозначения того, что некоторое поведение должно иметь место в определенной точке взаимодействия. 12.10 12.10. Комбинированные фрагменты и операторы 285 Оператор opt показывает, что его единственный операнд выполняется, если сторожевое условие истинно. В противном случае выполнение продолжается после комбинированного фрагмента. opt эквивалентен программной конструкции: if (условие1) then действие1 alt создает несколько ветвей. Оператор alt предоставляет выбор между рядом альтернатив. Каждый из его операндов имеет собственное сторожевое условие и будет выпол няться, если только условие истинно. Необязательный операнд, задан ный сторожевым условием [ else], выполняется, если ни одно из других сторожевых условий не является истинным. Это означает, что выполняться может только один из операндов alt, т. е. сторожевые условия всех операндов должны быть взаимоисклю чающими. Истинность более одного из сторожевых условий в любой момент времени является условием возникновения ошибки. Специфи кация UML не описывает поведение alt в этом случае. alt эквивалентен программной конструкции: if (условие1) then операнд 1 else if (условие2) then операнд 2 :A :B :C :D opt [условие] действие() alt операнд1() [условие1] [условие2] операнд2() [else] операнд3() sd OptAndAltSyntax делать это, если условие1 истинно делать это, если условие 2 истинно делать это, если ни одно из условий не является истинным делать это, если условие истинно Рис. 12.14. Синтаксис операторов opt и alt 286 Глава 12. Реализация прецедентов else if (условиеN) then операнд N else операнд M Как видите, оператор opt семантически эквивалентен оператору alt с одним операндом. В качестве примера использования opt и alt рассмотрим прецедент на рис. 12.15. Впервые прецедент ManageBasket был показан в разде ле 4.5.6. Это часть простой системы электронной коммерции. Он опи сывает процесс обновления количества объектов определенной товар ной позиции или полного удаления этой позиции из корзины для по купок ( ShoppingBasket) покупателя (Customer). На рис. 12.16 показана диаграмма классов анализа этого прецедента. Как видите, в ShoppingBasket находится один или более Item. Каждый из этих Item – это quantity (количество) конкретного Product. На диаграм ме классов анализа показывают только классы, атрибуты и операции, иллюстрирующие моделируемый момент. На данной диаграмме мы пытаемся показать совместную работу ShoppingBasket, Item и Product. И наконец, на рис. 12.17 показана диаграмма последовательностей, реализующая этот прецедент. Обратите внимание, что на данной диа грамме описана стратегия, согласно которой Item уничтожается, когда его quantity достигает нуля. Это вполне обоснованно, поскольку Item су ществует только для того, чтобы представлять quantity конкретного Основной поток: 1. Прецедент начинается, когда Customer выбирает товарную позицию в корзине. 2. Если Customer выбирает «delete item» 2.1. Система удаляет позицию из корзины. 3. Если Покупатель вводит новое количество 3.1. Система обновляет количество товаров в корзине. Прецедент: ManageBasket Предусловия: 1. Содержимое корзины для покупок является видимым. Краткое описание: Покупатель меняет количество товарных позиций в корзине. Постусловия: Нет. Альтернативные потоки: Нет. ID: 2 Главные актеры: Customer Второстепенные актеры: Нет. Рис. 12.15. Спецификация прецедента ManageBasket 12.10. Комбинированные фрагменты и операторы 287 Product в ShoppingBasket. Однако можно поспорить о необходимости та кого уровня детализации в анализе. Диаграмма последовательностей, явно не отображающая удаление Item, тоже была бы вполне допусти мой. 12.10.2. Организация итераций операторами loop и break loop позволяет моделировать итерацию. Очень часто на диаграммах последовательностей необходимо показать циклы. Сделать это можно с помощью операторов loop и break, как по казано на рис. 12.18. ShoppingBasket Item ManageBasket getItem():Item setQuantity():int quantity:int 0..* 1 Product productId:String name:String description:String price:double 0..* 0..* Рис. 12.16. Диаграмма классов анализа прецедента ManageBasket :ShoppingBasket item:Item getItem() alt setQuantity() [changeQuantity] [deleteItem] sd ManageBasket :Customer «destroy» «destroy» opt[ item.quantity = 0 ] Рис. 12.17. Диаграмма последовательностей прецедента ManageBasket 288 Глава 12. Реализация прецедентов Оператор loop действует следующим образом: loop min количество раз then while (условие истинно) loop (max min) количество раз В синтаксисе loop необходимо обратить внимание на следующие мо менты: • оператор loop без max, min или condition является бесконечным цик лом; • если задано только min, значит, max = min; • condition обычно является логическим выражением, но может быть и произвольным текстом, смысл которого ясен. На первый взгляд loop может показаться слишком сложным, но он мо жет использоваться для поддержки огромного числа разнообразных циклов. Некоторые из самых распространенных циклов перечислены в табл. 12.4. Когда сторожевое условие break становится истинным, выполняется операнд break, цикл прерывается. Оператор break может использоваться для обозначения условия пре кращения loop и того, что происходит после этого. У оператора break :A :B op1() sd LoopAndBreakSyntax loop [условие] op2() повторять, пока условие истинно break op3() op4() break должен быть глобальным по отношению к loop этого не происходит, если выполняется break при выходе из цикла сделать это loop min, max [условие] повторять минимальное количество раз, затем, пока условие истинно, повторять (max – min) количество раз Рис. 12.18. Отображение циклов на диаграмме последовательностей с помощью операторов loop и break 12.10. Комбинированные фрагменты и операторы 289 только одно сторожевое условие, и если оно истинно, исполняется тело break, а loop прерывается. Самое главное, что после завершения break loop не возобновляется. Таблица 12.4 Комбинированный фрагмент break логически находится вне цикла: он не является его частью. Поэтому фрагмент break всегда должен изобра жаться вне loop, но пересекаться с ним, как показано на рис. 12.18. Самым распространенным применением циклов является перебор коллекции объектов. Например, цикл может применяться как воз можная реализация операции findCourse(...) класса RegistrationManager (рис. 12.19). Эта операция возвращает объект Course с соответствующим именем ( name) или null, как показано на рис. 12.20. Имя конца ассоциации Тип цикла Семантика Выражение цикла while( true ) { тело } Бесконечный цикл. loop или loop * for i = n to m { тело } Повторяется ( m – n ) раз. loop n, m while( booleanExpression ) { тело } Повторяется, пока booleanEx pression (логическое выраже ние) истинно. loop [ booleanExpres sion ] repeat { тело } while( booleanExpression ) Выполнить один раз, а затем повторять, пока booleanEx pression истинно. loop 1, * [ booleanEx pression ] forEach object in collection { тело } Выполнить тело цикла по од ному разу для каждого объ екта в коллекции объектов. loop [ for each object in collectionOfObjects ] forEach object of class { тело } Выполнить тело цикла по од ному разу для каждого объ екта определенного класса. loop [ for each object in ClassName ] RegistrationManager Course 1 0..* courses Student 1 0..* students registration 0..* 0..* findCourse( name : String ) : Course findStudent( name : String ) : Student |