ガイドライン:
|
名前 | ある状態を別の状態から区別する文字列。状態は、名前のないことを意味する無名であってもかまいません。 |
入状時 / 退状時アクション | 状態の開始と終了時に行われるアクション |
内部遷移 | 状態の変化を伴わずに進行する遷移 |
サブ状態 | 状態のネスト構造で、個別の (逐次的にアクティブな) サブ状態と並列的な (並列的にアクティブな) サブ状態とがある |
遅延イベント | 該当の状態においては処理されず、その処理が後に回されて、ほかの状態にあるオブジェクトによって処理されるように待ち行列に入れられた、イベントのリスト |
図 1 に示したように、1 つのオブジェクトの状態マシンに定義できる特別な状態が 2 つあります。初期状態は、状態マシンまたはサブ状態のデフォルトの開始点を示します。初期状態は塗り潰された黒丸で表されます。最終状態は状態マシンでのアクションの実行が完了したこと、またはそれに包まれている状態が完了したことを示します。最終状態は内側が黒く塗りつぶされた二重丸で表されます。初期状態も最終状態も実際には擬似状態です。どちらも、名前を除いて、通常は正規の状態にはない部分を有する可能性があります。初期状態から最終状態への遷移には、関連する諸機能がすべて含まれる可能性があります。その中には、ガード条件やアクションが含まれますが、トリガ イベントは含まれません。
遷移は 2 つの状態の関係を表します。すなわち、最初の状態にあるオブジェクトがなんらかのアクションを行った後で、指定されたイベントが発生するか指定された条件が満たされたときに、2 番目の状態に移ることを示します。そのような状態の変化に際して、遷移は「発火する」と言います。遷移が発火するまでは、オブジェクトは「ソース」状態にあると言います。遷移が発火した後では、オブジェクトは「ターゲット」状態にあると言います。遷移には下に示すプロパティがあります。
ソース状態 | 遷移の影響を受ける状態。オブジェクトがソース状態にある場合、遷移のトリガとなるイベントをオブジェクトが受け取り、ガード条件がある場合にはそれが満たされたときに、進行中の遷移は発火することが可能となる |
イベント トリガ | ソース状態にあるオブジェクトが受け取ったときに、遷移を発火可能にする (ガード条件が満たされたものとして) イベント |
ガード条件 | イベント トリガが受け取られ遷移が引き起こされたときに評価される論理式。評価の結果が真であれば、遷移は発火可能となり、評価の結果が偽であれば遷移は発火不可能。同じイベントによって引き起こされる遷移がほかにない場合、イベントは失われる。 |
アクション | 状態遷移で表されるオブジェクトに直接作用し、そのオブジェクトに関連するほかのオブジェクトに間接的に作用する、実行可能な不可分の処理 |
ターゲット状態 | 遷移が完了した後で現れる状態 |
遷移には複数のソースがあることがあります。その場合、複数の並列する状態を結合して遷移は進みます。また、遷移のターゲットが複数の場合もあります。その場合、遷移の結果は複数の並列する状態に分かれます。
状態マシンという状況においては、イベントは状態遷移を引き起こす可能性のある刺激の発生です。イベントの例として、シグナル イベント、コール イベント、時間の経過、状態の変化などが挙げられます。シグナルやコールにはパラメータがあり、そのパラメータの値が遷移に使用されます。パラメータの例には、ガード条件やアクションの式があります。トリガがなくても遷移の発生は可能です。これは、イベント トリガなしの遷移として表されます。そのような遷移は、ソース状態のアクションが完了したときに暗黙的に引き起こされます。これは完了遷移とも呼ばれます。
遷移のトリガとなるイベントが発生した後でガード条件が評価されます。同じソース状態から同じイベント トリガによって複数の遷移を引き起こすことも可能です。ただし、その場合は、ガード条件は別々である必要があります。1 つのガード条件は遷移に関して 1 回だけ、イベントが発生したときに評価されます。論理式からオブジェクトの状態を参照できます。
アクションは実行可能な不可分の処理です。つまり、アクションはイベントによって割り込まれることがなく、最後まで遂行されます。これはほかのイベントによって割り込まれる可能性のある作業とは対照的です。アクションには、処理の呼び出し (状態マシンで表されるオブジェクト、それと関連するオブジェクトへの)、ほかのオブジェクトの作成と破棄、ほかのオブジェクトへのシグナルの送信などがあります。シグナルを送信する場合、シグナル名の前に send というキーワードが接頭辞として付加されます。
入状時アクションと退状時アクションを利用すると、該当の状態が始まる、または終わるたびに、それぞれ同じアクションが発動できます。そうすると、始まり、終わるたびに明示的にアクションを指定する必要がなくなります。入状時アクションと退状時アクションには引数またはガード条件を持たせることはできません。モデル要素のための状態マシンのトップレベルにある入状時アクションに、その要素が作成されたときに状態マシンが受け取る引数を表すパラメータを持たせることができます。
内部遷移を利用すると、状態の内部だけでイベントを処理できます。したがって、入状時アクションと退状時アクションを起動することが避けられます。内部遷移にはパラメータを伴うイベントとガード条件を持っていることがあり、基本的に、割り込みハンドラを表します。
遅延イベントとは、その処理の実施が保留されて、後でイベントが保留されない状態になったときに遅れて処理されるものです。その状態に達すると、そのイベントの発生が起動されて、それが新規に発生した場合のように遷移を引き起こします。遅延イベントを実装するためには、内部的なイベント キューを必要とします。遅延イベントが発生した場合には、キューに入れられます。オブジェクトがイベントを遅延させない状態に入るとすぐに、それらのイベントはキューから取り出されます。
簡単な状態にはサブ構造がありません。サブ状態 (ネストされた状態) のある状態を複合状態と呼びます。サブ状態は任意のレベルへネストされます。ネストされた状態マシンには初期状態と最終状態が 1 つずつあります。サブ状態は複雑でフラットな状態マシンを簡素化して見せるために使用します。つまり、複雑な状態のうちの一部はある特定の状況 (包含状態) においてのみ発生し得ることを示します。
図 3. サブ状態
包含する複合状態の外部のソースから開始された遷移のターゲットの状態は複合状態であることもサブ状態の場合もあります。複合状態がターゲットとされる場合、ネストされた状態マシンには初期状態が含まれている必要があります。複合状態の遷移が開始されてその入状時アクションが (もしあれば) 起動された後で、初期状態に制御が移されます。ネストされた状態がターゲットとされる場合、複合状態の入状時アクションが (もしあれば) 起動され、それからネストされた状態の入状時アクションが (もしあれば) 起動された後で、ネストされた状態に制御が移されます。
複合状態から発生する遷移はそのソースとして複合状態またはサブ状態を取ることがあります。どちらの場合でも、まずネストされている状態の方からほかに制御が移され (退状時アクションがある場合はそれも起動され)、次に複合状態からほかに制御が移され (退状時アクションがある場合はそれも起動され) ます。ソースが複合状態である遷移は基本的にネストされている状態マシンの作業に割り込みをかけることになります。
遷移が複合状態に入ると、ネストされた状態マシンのアクションは初期状態から再び開始されます (遷移がサブ状態を直接ターゲットとしていない場合)。ただし、別の指定がなされている場合を除きます。履歴状態を利用すると、複合状態から抜け出る直前のサブ状態に、状態マシンを再び入れられます。履歴状態の使用例を図 4 に示します。
図 4. 履歴状態
状態マシンは、オブジェクトのライフタイムにわたって、その振る舞いをモデル化するために最もよく使用されます。オブジェクトの振る舞いが状態に依存するときに、状態マシンは特に必要です。状態マシンを持つ可能性のあるオブジェクトには、クラス、サブシステム、ユース ケース、インターフェイス (インターフェイスを実現するオブジェクトによって満たされる必要がある状態を宣言するため) があります。
すべてのオブジェクトが状態マシンを必要とするとは限りません。オブジェクトの振る舞いが単純で、データを格納または取り出す程度のものである場合、オブジェクトの振る舞いは状態に関係がないため、その状態マシンにはほとんど意味がありません。
オブジェクトのライフタイムをモデリングするには、3 つの事柄が関係します。オブジェクトが応答する対象のイベントの指定、それらのイベントに対する応答、そして現在の振る舞いに対する過去の影響です。オブジェクトのライフタイムをモデリングすることには、イベントに対してオブジェクトが意味のある応答をするための順序を決めることも関係します。それは、オブジェクトが作成された時点からモデルが破棄されるまでに至ります。
オブジェクトのライフタイムをモデリングする手順は下記のとおりです。
抽象状態マシンとは、詳細をさらに追加してからでないと、実用的な目的に使用できない状態マシンです。一般的で再利用可能な振る舞いを定義するために使用できます。この振る舞いは後続のモデル要素でさらに精緻化します。
図 5. 抽象状態マシン
図 5 の抽象状態マシンを検討してみましょう。この図で示される単純な状態マシンは、イベント駆動システム内の多種多様な要素の振る舞い (自動「制御」) を最も抽象的なレベルで表したものです。それらの要素はすべてこの高水準のフォームを共有するにもかかわらず、さまざまな要素タイプはその目的に応じて実際に稼働するときには大幅に異なった、詳細な振る舞いを取る可能性があります。したがって、この状態マシンは、さまざまな特殊化したアクティブ クラスのルート クラスとして働く、なんらかの抽象クラスとして定義される可能性が最も高いでしょう。
そこで、継承を使用して、この抽象状態マシンを 2 とおりの違った方法で改良してみましょう。その 2 つの改良方法を R1 と R2 として、図 6 に示します。親クラスから継承した要素は、職別できるようにするために灰色で描いてあります。
図 6. 図 5 の状態マシンの 2 とおりの改良
この 2 つの改良結果には明白な違いがあります。それは、稼働状態をどのように分解するかという点と、元の「開始」遷移を拡張する方法に現れています。当然のことながら、どちらを選択するかは、改良の内容が明らかになった後でのみ決定できます。つまり、抽象クラスにおける 1 つの全面的な遷移だけではこの選択は行えません。
上記のタイプの改良では、遷移の始まりと遷移の終わりの両方を「継続」できる能力が基本的に重要です。入状点と最終状態を連続的な遷移で結合すれば、その意味を表すのに十分であると思われるかもしれません。残念ながら、拡張が必要な複数の異なる遷移がある場合は、これだけでは十分ではありません。
抽象的な振る舞いのパターンに必要なことは、単一の RTC 列の範囲内ですべて実行される 2 つ以上の遷移セグメントを連続的につなぐ方法です。このことは、階層的な状態に入っていく遷移は前の部分と後の部分の 2 つに分けられることを意味します。前の部分は状態の境界のところで終了し、後の拡張部分は新しい状態の中に入っていきます。同様に、階層的にネストされた状態から外へ去り行く遷移も前の部分と後の部分の 2 つに分けられます。前の部分は包含されている状態の境界で終了し、後の部分は境界からターゲットの状態の中に入っていきます。この効果は UML において連鎖状態の概念を導入することによって達成されます。これは UML の状態概念のステレオタイプである (≪chainState≫) によってモデル化されます。これは、唯一の目的が自動的な (トリガなしの) 遷移をさらに入力遷移へと「連鎖」させる状態です。連鎖状態には内部構造がありません。つまり、入状時アクションも、内部的な作業も、退状時アクションもありません。また、連鎖状態にはイベントによって起動される遷移もありません。連鎖状態は任意の数の入力状態を取ることができます。連鎖状態はトリガイベントのない、1 つの去り行く遷移を持つことが可能です。この遷移は、入力遷移によって状態が有効になったときに、自動的に発火します。この状態の目的は入力遷移を別の出力遷移につなげることです。入力遷移と連鎖される出力遷移との間で、前者は包含する状態の内側の別の状態につながり、後者は包含する状態の外側の別の状態につながります。連鎖状態を導入する目的は、包含する状態の内部仕様を外部の環境から隔離すること、すなわち、カプセル化することです。
実際、連鎖状態は、ある遷移を特定の連続的な遷移へとつなげる働きをする、「通路」状態を表します。連続的な遷移が定義されていない場合、遷移は連鎖状態に入って止まります。そして、包含する状態の中のなんらかの遷移が処理を続行させるために発火する必要が出てきます。
図 7 の状態マシンのセグメントの例は連鎖状態とその表記法を示しています。状態マシン図において、連鎖状態は適切な階層状態の中に位置している小さな白丸によって表されています (この表記法は連鎖状態と類似した初期状態と最終状態に似ています)。丸は連鎖状態のステレオタイプを表すアイコンであり、通常は便宜的に境界の近くに描かれます (実際、カプセル上のポートの表記法に似て、包含する状態の境界上にそれらのアイ コンを描く、表記法の変形もあります)。
図 7. 連鎖状態と連鎖された遷移
この例における連鎖された遷移は 3 つの連鎖された遷移のセグメント、e1/a11-/a12-/a13 で構成されています。シグナル e1 が受け取られると、e1/a11 というラベルが付けられた遷移が開始され、a11 のアクションが実行されて、連鎖状態の c1 に達します。その後、c1 と c2 との間の連続的な遷移が開始されて、最後に c2 も連鎖状態なので、c2 から S21 への遷移が開始されます。このパスに沿った状態のすべてに退状時アクションと入状時アクションがあるとすると、実際にアクションが進行する順序は次のようになります。
このすべてが単一の RTC 列の範囲内ですべて実行されます。
これと対照的に、直接的な遷移 e2/a2 のアクションの実行順序は次のようになります。
Rational Unified Process
|