На этом шаге рассмотрим расширенные состояния и преходы в UML.
Моделирование самого разного поведения в UML в большинстве случаев требует использования только базовых средств состояний и переходов UML. Применяя их, вы можете специфицировать простой автомат, а это означает, что ваши поведенческие модели будут описаны лишь дугами (переходами) и вершинами (состояниями) – ничем более.
Автоматы UML включают множество средств, помогающих управлять сложными поведенческими моделями. Эти средства часто позволяют уменьшить количество необходимых состояний и переходов, а также смоделировать множество общих и иногда довольно сложных идиом, которые в противном случае пришлось бы отображать в виде простых автоматов. Некоторые из этих расширенных средств включают входные и выходные эффекты, внутренние переходы, деятельности и отложенные события; изображаются они в виде строк текста внутри пиктограммы состояния, как показано на рис. 1.
Рис.1. Расширенные состояния и переходы
Иногда моделируемая ситуация требует выполнения некоторого установочного действия при входе в состояние – независимо от того, какой переход привел вас сюда. Аналогичным образом, когда объект покидает состояние, нужно выполнить некоторую очистку независимо от того, какой переход из него уводит. Например, в системе управления ракетой вы можете пожелать явно объявить эффект onTrack (ведетПреследование), когда система входит в состояние Tracking (Преследование), и offTrack (прекратилаПреследование) – когда покидает его. Используя простой автомат, можно достичь подобного эффекта, помещая эти действия соответственно на каждом входном и выходном переходе. Однако здесь велика вероятность ошибиться: необходимо постоянно помнить, что действия нужно создавать при добавлении каждого нового перехода. Более того, модификация действия означает, что будут затронуты все соседние переходы.
Как показано на рис. 1, UML предусматривает сокращение для этой идиомы. В пиктограмму состояния можно включить входной эффект (помеченный ключевым словом entry) и выходной эффект (помеченный ключевым словом exit), – каждый с указанием соответствующего действия. Всякий раз при входе в состояние вызывается входное действие, а при выходе из него – выходное.
Входной и выходной эффекты могут не иметь аргументов или защитных условий, но первый из них на верхнем уровне автомата класса может иметь параметры аргументов, которые автомат принимает при создании объекта.
Внутри состояния часто возникает необходимость обрабатывать определенные события, не покидая его. В таком случае можно говорить о внутренних переходах, которые имеют тонкое отличие от переходов в себя. Когда дело касается перехода в себя событие инициирует переход, объект покидает состояние, выполняется некоторое действие (если оно есть) и затем объект вновь входит в то же состояние. Поскольку данный переход выходит и входит в состояние, он инициирует действие выхода, затем действие самого перехода и, наконец, действие входа.
Однако предположим, что вы хотите обработать событие, не выполняя при этом входные и выходные действия. UML предусматривает сокращение для этой идиомы в виде внутреннего перехода.
Внутренний переход (internal transition) – это такой переход, который реагирует на событие соответствующим эффектом, не изменяя состояния. На рис. 1 событие newTarget (новаяЦель) помечает внутренний переход; если это событие происходит, когда объект находится в состоянии Tracking (Преследование), то при этом выполняется действие tracker.Acquire() (преследователь.Получить()), но состояние остается прежним, и никакого входного или выходного эффекта не наблюдается. Внутренний переход символизируется включением строки перехода (вместе с именем события, необязательным защитным условием и эффектом) в символ состояния вместо стрелки перехода. Отметим, что слова entry (вход), exit (выход) и do (действовать) являются ключевыми и не могут быть использованы в качестве имен событий. Всякий раз, когда объект находится в некотором состоянии и происходит событие, которым помечен внутренний переход, выполняется соответствующий эффект, но объект при этом не покидает состояния и не возвращается в него повторно. Таким образом, событие обрабатывается без вызова действий выхода и входа.
Внутренние переходы могут включать события с параметрами и защитными условиями.
Когда объект находится в некоем состоянии, он обычно простаивает, ожидая наступления события. Однако иногда становится необходимо смоделировать некую деятельность, выполняемую в этом состоянии (do-activity). Иными словами, пребывая в состоянии, объект может что-либо делать до тех пор, пока это не будет прервано событием. Например, пребывая в состоянии преследования – Tracking, объект может следовать за целью (followTarget). Как показано на рис. 1, в UML применяется специальный переход do, описывающий работу, которая должна выполняться внутри состояния после того, как будет выполнено входное действие. Можно также специфицировать поведение как последовательность действий – например, do/op1(a);op2(b);op3(c). Если появление события вызовет переход, который приведет к выходу из состояния, любая выполняемая в состоянии деятельность немедленно прекратится.
Деятельность внутри состояния – это эквивалент входного эффекта, который начинает деятельность при входе в состояние, и выходного эффекта, который останавливает ее при выходе из состояния.
Рассмотрим такое состояние, как Tracking (Преследование). Предположим, что есть только один переход к этому состоянию, вызванный событием contact (контакт). Пока объект находится в состоянии Tracking, любые события, отличные от contact, а также от тех, которые обрабатываются подсостояниями, будут потеряны. Это значит, что событие может произойти, но будет проигнорировано и в результате не вызовет никаких действий.
В любой ситуации, связанной с моделированием, важно распознавать одни события и игнорировать другие. Первые вы включаете в модель как события, инициирующие переходы; вторые просто оставляете без внимания. Однако в определенных ситуациях необходимо принимать некоторые события и при этом откладывать реакцию на них на более позднее время. Например, пока объект находится в состоянии Tracking, придется откладывать реакцию на такие сигналы, как selfTest (самопроверка), посылаемый агентами поддержки работы системы.
В UML подобное поведение можно специфицировать, используя отложенные события. Отложенное событие (deferred event) – такое, обработка которого откладывается до тех пор, пока объект не перейдет в другое состояние. Если событие в этом новом состоянии уже не является отложенным, оно обрабатывается и может вызвать переход, как если бы оно произошло только что. Если автомат проходит через ряд состояний, в которых данное событие является отложенным, оно сохраняется до тех пор, пока не наступит состояние, в котором оно перестанет считаться таковым. За этот период могут возникать другие события, не являющиеся отложенными. Как видно из рис. 1, отложенное событие можно отметить, добавив к его имени ключевое слово defer. В этом примере события selfTest могут иметь место в состоянии Tracking, но удерживаются до тех пор, пока объект не придет в состояние Engaging (Включение); тогда они обрабатываются так, будто произошли только что.
Реализация отложенных событий требует наличия их внутренней очередности. Если происходит событие, которое помечено как отложенное, оно помещается в очередь. События извлекаются из нее, как только объект переходит в состояние, в котором они перестают считаться отложенными.
К автомату можно обратиться из другого автомата. Такие автоматы называются вложенными (submachines). Их удобно использовать, прорабатывая структуру крупных моделей состояний.
На следующем шаге рассмотрим последовательные подсостояния в UML.