EA-可执行状态机-延迟事件模式
前言
因为最近在做EA的模型搭建,查阅资料的时候,发现这篇示例说明比较实用,但是英文版理解起来比较慢,中文版在火龙果网站有,但是机翻增加了理解难度,因此,我打算整理一下中文版的翻译,作为学习记录。
火龙果网站中的EA软件参考文档【中文】
———————————————————————————
Enterprise Architect支持延迟事件模式。
在状态中创建延迟事件:
- 为状态(state)创建自我过渡(self transition)。
- 将过渡的种类更改为“内部过渡”。
- 指定触发器(Trigger)成为你需要延迟的事件。
- 在“效果”(Effect)字段中,键入“ defer();”。
进行模拟:
- 打开"模拟窗口":选择“模拟>动态模拟>模拟器>打开模拟窗口”。
打开"模拟事件窗口":选择“模拟>动态模拟>事件”。
- 模拟器事件窗口(Simulation Event Window)可帮助您触发事件;双击“等待触发器”列中的触发器。

- Simulation窗口以文本形式显示执行。您可以在Simulator命令行中键入“ dump”,以显示队列中延迟了多少个事件。
输出可能类似于以下内容:
24850060]事件池:[NEW,NEW,NEW,NEW,NEW,]
延迟事件示例
本示例显示了使用“延迟事件”的模型,“模拟事件”窗口显示了所有可用事件。
我们首先建立上下文(context)(包含状态机的类中元素),在简单的上下文中模拟它们,并从外部引发事件;然后在使用Send事件机制的客户端-服务器(client-server)上下文中进行仿真。
创建上下文和状态机
创建服务器上下文

创建一个类图:
- 一个类元素:TransactionServer ,向其中添加一个状态机,名为ServerStateMachine
- 一个类元素TestClient ,向其中添加一个状态机,名为ClientStateMachine
- 从TestClient到TransactionServer的关联(association),目标角色名为server。
为 ServerStateMachine 建模

- 向状态机图中添加一个初始化结点,名为Initial ,然后过渡到状态idle
- 转换(事件NEW_REQUEST作为触发器)到状态busy
- 过渡(使用事件QUIT作为触发)到最终状态Final
- 转换(事件AUTHORIZED作为触发器)到idle
- 转换为繁忙状态 (事件NEW_REQUEST作为触发器,defer();作为效果(effect))
ClientStateMachine的 建模

- 在状态机图中添加一个初始化结点initial,转换到状态State0
- 转换(以事件RUN_TEST作为触发器)到状态State1 。
- 过渡到状态State2 (转移中的效果effect为:%SEND_EVENT(“ NEW_REQUEST”,CONTEXT_REF(服务器))%;) 。
- 过渡到状态State3 (转移中的效果effect为:%SEND_EVENT(“ NEW_REQUEST”,CONTEXT_REF(server))%;)。
- 过渡到状态State4 (转移中的效果effect为:“%BROADCAST_EVENT(“ NEW_REQUEST”)%;)。
- 过渡到状态State5(转移中的效果effect为:%SEND_EVENT( “AUTHORIZED”,CONTEXT_REF(server))%)。
- 过渡到最终状态Final。
在简单环境中进行仿真
创建仿真工件

- 创建名称为Simulation with Deferred Event的可执行状态机工件,并将”语言“(“ Language”)字段设置为JavaScript。【此处的语言设置也可以是java、C++、C】
- 将其放大,然后按住Ctrl键并将TransactionServer元素拖动到工件上,并将其粘贴为可执行状态机的一个属性,命名为server。
运行模拟
- 选择工件,然后选择“模拟>可执行状态>状态机>生成,构建和运行”选项,并为您的代码指定目录(注意:目录中的所有文件将在模拟开始前被删除)。
- 单击生成按钮。(Generate)
-
- 选择“模拟>动态模拟>事件”选项,以打开“模拟事件”窗口。

当模拟开始时, idle状态将变为活动状态。

- 在“模拟事件”窗口中双击NEW_REQUEST,将其作为触发器执行;退出idle状态并激活busy状态 。

- 在“模拟事件”窗口中双击NEW_REQUEST,再次将其作为触发器执行; busy状态保持激活状态,同时,一个NEW_REQUEST的实被例添加入事件池。
- 在“模拟事件”窗口中双击NEW_REQUEST,第三次将其作为触发器执行;busy状态保持激活状态,同时,一个NEW_REQUEST的实被例添加入事件池。
- 在“模拟”窗口的命令行中键入dump ;请注意,此时事件池具有两个NEW_REQUEST实例。

- 在“模拟事件”窗口中双击AUTHORIZED,将其作为触发器执行;如下动作将会发生:
- 从busy状态退出,idle状态被激活,成为活跃状态;
- 一个NEW_REQUEST事件从事件池中被检索出来,busy状态退出,busy状态被激活,成为活跃状态;
- 在“模拟”窗口命令行中键入dump ;现在,事件池中只剩余一个NEW_REQUEST实例。

通过发送/广播事件进行交互式模拟
创建仿真工件

- 创建一个可执行状态机工件,命名为“ Interactive Simulation with Deferred Event”,并将“ Language”字段设置为JavaScript;拉大元素范围。
- 按住Ctrl键,将TransactionServer元素拖放到工件上,并将其作为可执行状态机的一个属性,命名为server。
- 按住Ctrl键,将TestClient元素拖放到工件上,并将其作为可执行状态机的一个属性,命名为client。
- 创建一个从client到server的连接(connector)。
- 单击连接器,然后按Ctrl + L以选择从TestClient元素到TransactionServer元素的关联。
运行交互式仿真
-
以与简单上下文相同的方式启动仿真。
模拟开始后, client端将保持在State0 ,而server端将保持idle状态 。

-
在“模拟事件”窗口中双击RUN_TEST,从而触发该事件。 NEW_REQUEST事件将被触发3次(由SEND_EVENT和BROADCAST_EVENT触发),而AUTHORIZED事件将由SEND_EVENT触发1次。

-
在“模拟”窗口命令行中键入dump ,事件池中还有一个NEW_REQUEST实例。结果与我们的手动触发测试相符。