Самоучитель UML — страница 20 из 35

Составное состояние (composite state) – такое сложное состояние, которое состоит из других вложенных в него состояний. Последние будут выступать по отношению к первому как подсостояния (substate). Хотя между ними имеет место отношение композиции, графически все вершины диаграммы, которые соответствуют вложенным состояниям, изображаются внутри символа составного состояния (рис. 6.6). В этом случае размеры графического символа составного состояния увеличиваются, так чтобы вместить в себя все подсостояния.

Рис. 6.6. Графическое представление составного состояния с двумя вложенными в него последовательными подсостояниями

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

Последовательные подсостояния

Последовательные подсостояния (sequential substates) используются для моделирования такого поведения объекта, во время которого в каждый момент времени объект может находиться в одном и только одном подсостояний. Поведение объекта в этом случае представляет собой последовательную смену подсостояний, начиная от начального и заканчивая конечным подсостояниями. Хотя объект продолжает находиться в составном состоянии, введение в рассмотрение последовательных подсостояний позволяет учесть более тонкие логические аспекты его внутреннего поведения.

Для примера рассмотрим в качестве моделируемого объекта обычный телефонный аппарат. Он может находиться в различных состояниях, одним из которых является состояние дозвона до абонента. Очевидно, для того чтобы позвонить, необходимо снять телефонную трубку, услышать тоновый сигнал, после чего набрать нужный телефонный номер. Таким образом, состояние дозвона до абонента является составным и состоит из двух последовательных подсостояний: «поднять телефонную трубку» и «набрать телефонный номер». Фрагмент диаграммы состояний для этого примера содержит одно составное состояние и два последовательных подсостояний (рис. 6.7).

Рис. 6.7. Пример составного состояния с двумя вложенными последовательными подсостояниями

Некоторых пояснений могут потребовать переходы. Два из них специфицируют событие-триггер набор цифры, которое имеет имя «цифра» с параметром "п". В качестве параметра, как нетрудно предположить, выступает отдельная цифра на диске телефонного аппарата. Переход из начального под-состояния нетриггерный, поскольку он не содержит никакой строки текста. Последний переход в конечное подсостояние не имеет события-триггера, но имеет сторожевое условие, проверяющее правильность набранного номера абонента. Только в случае истинности этого условия телефонный аппарат может перейти в конечное подсостояние, которое характеризует суперсостояние «дозвон до абонента» в целом.

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

Это можно объяснить следующим образом. Каждая совокупность вложенных последовательных подсостояний представляет собой подавтомат того автомата, которому принадлежит рассматриваемое составное состояние. Поскольку каждый автомат может иметь по определению единственное начальное и единственное конечное состояния, то для подавтомата это условие также должно выполняться (рис. 6.7).

Параллельные подсостояния

Параллельные подсостояния (concurrent substates) позволяют специфицировать два и более подавтомата, которые могут выполняться параллельно внутри составного события. Каждый из подавтоматов занимает некоторую область (регион) внутри составного состояния, которая отделяется от остальных горизонтальной пунктирной линией. Если на диаграмме состояний имеется составное состояние с вложенными параллельными подсостояниями, то объект может одновременно находиться в каждом из этих подсостояний.

Однако отдельные параллельные подсостояния могут, в свою очередь, состоять из нескольких последовательных подсостояний (подавтоматы 1 и 2 на рис. 6.8). В этом случае по определению объект может находиться только в одном из последовательных подсостояний подавтомата. Таким образом, для абстрактного примера (рис. 6.8) допустимо одновременное нахождение объекта в подсостояниях (1, 3, 4), (2, 3, 4), (1, 3, 5), (2, 3, 5). Недопустимо нахождение объекта одновременно в подсостояниях (1, 2,3) или (3, 4, 5).

Рис. 6.8. Графическое изображение составного состояния с вложенными параллельными подсостояниями

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

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

В некоторых случаях бывает желательно скрыть внутреннюю структуру составного состояния. Например, отдельный подавтомат, специфицирующий составное состояние, может быть настолько большим по масштабу, что его визуализация затруднит общее представление диаграммы состояний. В подобной ситуации допускается не раскрывать на исходной диаграмме состояний данное составное состояние, а указать в правом нижнем углу специальный символ-пиктограмму (рис. 6.9). В последующем диаграмма состояний для соответствующего подавтомата может быть изображена отдельно от основной с необходимыми комментариями.

Рис. 6.9. Составное состояние со скрытой внутренней структурой и специальной пиктограммой

6.5. Историческое состояние

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

Историческое состояние (history state) применяется в контексте составного состояния. Оно используется для запоминания того из последовательных подсостояний, которое было текущим в момент выхода из составного состояния. При этом существует две разновидности исторического состояния: недавнее и давнее (рис. 6.10).

Рис. 6.10. Графическое изображение недавнего (а) и давнего (б) исторического состояния

Недавнее историческое состояние (shallow history state) обозначается в форме небольшой окружности, в которую помещена латинская буква "Н" (рис. 6.10, а). Это состояние обладает следующей семантикой. Во-первых, оно является первым подсостоянием в составном состоянии, и переход извне в это составное состояние должен вести непосредственно в это историческое состояние. Во-вторых, при первом попадании в недавнее историческое состояние оно не хранит никакой истории (история пуста). Другими словами, при первом переходе в недавнее историческое состояние оно заменяет собой начальное состояние подавтомата.

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

Историческое состояние теряет свою историю в тот момент, когда подавтомат доходит до своего конечного состояния. При этом недавнее историческое состояние запоминает историю только того подавтомата, к которому он относится. Другими словами, этот тип состояния способен запомнить историю только одного с ним уровня вложенности.

С другой стороны, запомненное состояние, в свою очередь, также может являться составным состоянием. Давнее историческое состояние (deep history state) обозначается в форме небольшой окружности, в которую помещена латинская буква "Н" с символом "*" (рис. 6.10, б) и служит для запоминания всех подсостояний любого уровня вложенности для текущего подавтомата.

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

В этом случае составное состояние «работа редактора» должно содержать вложенное историческое подсостояние, которое запоминает выполненную работу. После окончания дозвона и загрузки новой почты (в случае ее наличия) мы должны вернуться к сохраненному фрагменту нашего сообщения и продолжить работу редактора программы.