第6回「」は、オブジェクト間のコラボレーションを表現する相互作用図について説明しました。 相互作用図はオブジェクト指向の基本的考え方である自律分散協調動作をモデリングするものです。 UMLには、メッセージの時系列を重視するシーケンス図とオブジェクト間のコラボレーションを簡単に表現するコラボレーション図の2つのダイアグラムが定義されています。 今回は「振る舞いをUMLで表現する」の第2回として、UMLのもう1つの動的モデルである ステートチャート図について説明します。 ステートチャート図はある特定のオブジェクトに注目して、そのライフサイクルをモデリングするものです。 はじめに前回の復習の意味で、最後に宿題として挙げておきました問題について考えてみましょう。 前回の説明では、お母さんと妹が協力して弁当を作るというシナリオで相互作用モデルを作成しました。 これとはちょっと違う視点で相互作用モデルを考えてみましょう。 前回の問題 Aさんは卵焼き弁当を欲しいと思ったとします。 モデルに登場するオブジェクトは弁当箱、炊飯器、米びつ、フライパンおよび冷蔵庫です。 冷蔵庫には卵が入っています。 これらのオブジェクトが協力してAさんの要求をどのように達成すればよいかを、オブジェクトを擬人化してちょっと遊び心で考えてください。 子ども向け漫画やアニメの世界では、しばしば「もの」を擬人化することがあります。 例えばディズニーの『美女と野獣』では、ろうそく、時計、ポットなどが人のように話したり歩いたりします。 それぞれは自分の責務・役割を持っています。 ろうそくは周りを照らし、時計は時刻を示し、ポットはお茶をサービスします。 このようなアニメ風のシナリオで弁当作りの問題を考えてみましょう。 図6 「弁当作成」第3のモデル 第3のモデルの コラボレーション図と シーケンス図は 宿題としておきますので、皆さんで考えてください。 オブジェクトの状態 次は ステートチャート図の説明に入りますが、その前にオブジェクトの状態について考えてみましょう。 オブジェクトの状態は変化します。 その状態は属性の値または他オブジェクトとのリンクで表現することができます。 図7は、米びつの在庫量を属性で表現した例です。 2合入っている状態から1合取り出すと1合入っている状態になります。 そこからさらに1合取り出すと空の状態となり、そこに2合追加すると2合入っている状態に戻ります。 これらの状態はオブジェクトの属性の値で表現することができます。 プロフィール 河合昭男(かわいあきお) 大阪大学理学部数学科卒業、日本ユニシス株式会社にてメインフレームのOS保守、性能評価の後、PCのGUI系基本ソフト開発、クライアント/サーバシステム開発を通してオブジェクト指向分析・設計に携わる。 オブジェクト指向の本質を追究すべく1998年に独立後、有限会社オブジェクトデザイン研究所設立、理論と実践を目指し現在に至る。 事業模型倶楽部、日本XPユーザ会、パターン言語のコミュニティなどソフトウェア新技術の学習と普及を行うコミュニティ活動に参画。 著書『まるごと図解 最新オブジェクト指向がわかる』(技術評論社)、『まるごと図解 最新UMLがわかる』(技術評論社)。 『UML Press』(技術評論社)、『ソリューションIT』(リックテレコム)ほかの専門誌に多数執筆。 ホームページ「」。
次の
図2 はガード条件の使い方を誤ってしまっている典型的な例です。 この状態遷移図に従って実装された「保温器」は、おそらく「現在温度」が「上限温度」を超えても「ヒーター」がOFFにならず、どこまでも加熱し続けてしまいます 場合によってはペットの熱帯魚が全滅してしまったり、火災が発生してしまったりします。 このステートマシン図でまずいのは「加熱中」状態と「非加熱中」状態の間の遷移にかけられているガード条件の部分です。 おそらく、このようなステートマシン図を描く人は『これらのガード条件はいつでも常にチェックされていて、その条件が満たされたら遷移が起こる』という間違った解釈をしてしまっているのでしょう。 この例では、トリガー イベント の指定がされていない自動遷移 ラムダ遷移 に対してガード条件がかけられている形式になっているので、このステートマシン図で示されている動作を「保温器」インスタンスが生成された時から順に正確に追ってみると以下のようになります。 最初に現在の状態が「加熱中」になる。 「加熱中」状態のentryアクション「ヒーターON」が実行される。 entryアクションの実行が終わったら「非加熱中」状態に自動遷移しようとする。 この時点ではヒーターがONになったばかりなので、おそらく「現在温度」は「上限温度」を超えていない。 ガード条件を満たさないのでこの自動遷移はブロック 阻止 される 現在の状態は「加熱中」のまま。 以後、「電源OFF」イベントが起こらない限り現在の状態は「加熱中」状態のままで、前のステップでブロックされた自動遷移も二度と起こらない ここにかかっているガード条件の評価も行われない ので、電源入りっぱなしの「ヒーター」はいつまでも加熱を続ける...。 決して「ガード条件はいつでもチェックされている」と勘違いしないでください。 では、この保温器を正しく動作させるためにはどのようなステートマシン図を描けば良いのでしょうか? ひとつの方法として 図3 のようにポーリング的な自己遷移を追加するやり方が考えられます。 このステートマシン図は「加熱中」状態および「非加熱中」状態に「after 1秒 」というトリガーが付けられた自己遷移が追加されていることを除いて 図2 のステートマシン図と同じです。 ここで使われている「after 時間 」という記述はUMLで用意されているTimeEventの一種で、この例では現在の状態が「加熱中」状態 または「非加熱中」状態 になった時から1秒後にafterイベントが自動的に発火し、一度現在の状態を抜けてから再度同じ状態に遷移します。 つまり、現在の状態が「加熱中」 または「非加熱中」 状態にある間、常に1秒間隔で現在の状態に入りなおしているということです。 このようにしておくと、1秒間隔で現在の状態が変わる 入りなおされる ので、その都度自動遷移 ラムダ遷移 を起こそうとしてガード条件が評価されるようになります。 他に 図4 のような記述をすることもできそうです。 このステートマシン図では 図2 でガード条件になっていた部分が「when 条件式 」という記述に置き換わっています。 この記述はUMLで用意されているChangeEventの利用例になっています。 whenイベントは「条件式の値がいつでもチェックされていて、この式の値が偽 false から真 true に変わった時に発火する」というように解釈されます。 このような便利なモデル要素は知らないと損ですよね。 さて、図4 のステートマシン図は一見良さそう 正しく動作しそう に思えるかもしれませんが、実はまだあまいところがあります。 whenイベントは「条件式の値が偽 false から真 true に変わった時に発火する」ので、既にその条件式を満たしている状況の時にはこのイベントは起こりません。 そのため、図4 のステートマシン図では「保温器」のインスタンスが生成された時に既に「現在温度」が「上限温度」を超えていた場合、「ヒーター」がONになりっぱなしになって温度がどんどん上がっていってしまいます。 このような状況を避けるため、たとえば 図5 のように初期状態からの遷移を条件によって振り分けるようにするなどの対処をしておくと良いでしょう。 その3: 履歴状態の取り扱い UMLのステートマシン図には履歴状態 History State という便利なモデル要素が用意されています。 履歴状態は、ある入れ子の状態遷移から抜けて別の状態に移る際に直前にどの状態にいたか記憶しておき、後でその直前にいた状態に現在の状態を戻してくれる機構を表現しています。 このような便利な履歴状態ですが、なぜか正しく表記されることが少ないようです。 例として前出のエアコンの状態遷移を考えてみてください。 ただし、今度は「運転停止」「運転開始」で運転を再開した時に、直前の運転モードで運転再開するようにしたいものとします。 図9 は良く見られる「間違った」履歴状態の使い方の例です。 このステートマシン図中で小さい丸で囲まれた「H」のアイコンが履歴状態です。 おそらく、このようなステートマシン図を描く人の気持ちとしては、『「運転中」状態に遷移してきた時、この入れ子状態に置いてある履歴状態が直前に居た入れ子の状態 「冷房」「暖房」「除湿」のいずれか に自動的に遷移してくれる んじゃないかな 』といった感じだと思うのですが、これでは履歴状態は機能しません 前出の 図6 と同じように非決定な状態遷移図になってしまいます。 UMLの仕様書をしっかり読んでみると、「履歴状態に入ってくる遷移線によって状態遷移が起こる場合、履歴状態は現在の状態を記憶されている直前に居た状態にする」という旨の記述が見つかります。 つまり、履歴状態のアイコンに入っていく遷移線が無いと履歴状態はその機能を発揮しないんですね。 図10 では、履歴状態のアイコンに遷移していく遷移線を明示してみました。 「停止中」状態で「運転開始」イベントが発生すると履歴状態に遷移するので、履歴状態は記憶されている直前に居た入れ子の状態 「冷房」「暖房」「除湿」のいずれか に現在の状態を遷移してくれます。 このステートマシン図は一見良さそう 正しそう に思えるのですが、まだ甘いところがあります。 それは『まだ「運転中」状態に一度も遷移していない時に履歴状態へ遷移が起こったらどうすれば良いのか?』が明示されていないという点です。 この「エアコン」のインスタンス生成直後、現在の状態は「停止中」にあります。 その状況で「運転開始」イベントが起こると「運転中」状態中の履歴状態に遷移してきますが、この時点ではこの履歴状態は「直前にどの状態に居た」という情報を記憶していません 初めて「運転中」状態に遷移してきたのですから当然ですね... ということで、このステートマシン図はまだ「非決定な 現在の状態が特定できない場合がある 状態遷移図」になっています。 このように非決定な状態遷移になってしまうことを避けるために、 初期状態と同じように 最大1本だけ履歴状態から出て行く遷移線を引くことができます 状態遷移が決定的にできる場合はこのような遷移線を引かなくてもOKです。 この遷移線は、履歴状態が直前に居た状態に関する記憶を持たない場合のデフォルトの遷移先として用いられます。 このような遷移線を追加した正しいステートマシン図を 図11 に示します。 このステートマシン図だと、このエアコンはたとえば以下のような動作をします 適当なシナリオを想定しています。 インスタンス生成直後。 現在の状態は「停止中」状態になる。 「運転開始」イベントが発生すると、「運転中」状態の中の履歴状態への遷移が起こる。 この時点で履歴状態は直前に居た状態に対する記憶を持たないので、現在の状態をデフォルト遷移で指定されている「冷房」にする。 「運転切替」イベントが発生し、現在の状態が「暖房」になる。 もう一回「運転切替」イベントが発生し、現在の状態が「除湿」になる。 この時点で「運転停止」イベントが発生し、現在の状態は「停止中」に遷移する。 ここで、履歴状態は直前に「除湿」状態に居たことを記憶する。 「停止中」の状態で、再度「運転開始」イベントが発生すると、「運転中」状態の中の履歴状態への遷移が起こる。 この時点で履歴状態は直前にいた状態に対する記憶を持っているので、現在の状態を「除湿」に戻す デフォルト遷移は無視される。 これで、このエアコンは運転再開する毎にいちいち運転モードを指定しなおす必要がなくなりました。 おわりに UMLのステートマシン図は、デビッド・ハレル氏が提唱したハレルチャート ハレルの状態遷移図 をベースに、さらに様々な仕組みを拡張したとても高機能な状態遷移図になっています。 その高機能さ故にすべての機能を使い切るのは難しいですが、「こういう状態変化を表現したいんだけど、うまく描けないなぁ... 」などという時にUMLの仕様書を読み直して調べてみると「あまりよく知られていないけれど 実は とても便利なモデル要素」が見つかったりすることがあります。 そういう時、「あぁ、多くの人達が長い時間をかけていろいろ試行錯誤してきた結果のノウハウがUML仕様の一部としてまとめられているんだなぁ」ということを実感します。 こういった「先人達の知恵」は有難く有効活用していきたいものですね。
次の
Part1:UMLとは何か? とは、Unified Modeling Language( 統一モデリング言語)の略語で、分析から設計、実装まで、オブジェクト指向開発に一貫して用いられるモデリング手法です。 UML図とは、ソフトウェアシステムの成果物を記述、視覚化、構築、文書化するために使用される国際的な業界標準のグラフィカル表記法です。 UMLが登場するまではモデリング手法が雑多であったため、情報交換などコミュニケーション間での問題が起こりがちでした。 そのため様々な手法を統一することによってUMLが開発されました。 手法の統一は設計書の読みやすさや交流における効率化などに大きく役立ちます。 ではUMLの活用で実際に何をしていくのかについて、主な例を以下に挙げます。 分類 種類 表現内容 構造図 クラス図 各クラスの構造、クラス間の関係 コンポーネント図 ソフトウェアを構成するコンポーネント、及びその間の依存関係 配置図 システムの物理的なレイアウト(配置) パッケージ図 クラスなどモデル要素のグルーピング及びグループ パッケージ 間の関係 振る舞い図 ユースケース図 システムが提供する機能、及び利用者や他システムなどの外部との関係 相互作用図 シーケンス図 時間軸に沿ったオブジェクトの相互作用 コラボレーション図 オブジェクト間の相互作用 ステートチャート オブジェクトの生成から消滅までの状態の遷移と変化 アクティビティ図 システム動作の流れ 1. クラス図はアプリケーションのオブジェクト及び情報構造だけでなく、ユーザーとの通信も記述されます。 UMLクラス図には、クラス、オブジェクト、集合、依存関係、合成、汎化などの要素が含まれます。 システムを構成するコンポーネント、及び各コンポーネント間の関係を記述します。 これはハードウェアのトポロジーシステムを視覚化し、物理ハードウェア要素とそれらの間の通信関係をモデル化し、システムのアーキテクチャを計画するために使用されます。 ノード、コンポーネント、依存関係などが含まれます。 パッケージ図はサブシステムまたはモジュール間の構造と依存関係を示すことができます。 パッケージはファイルフォルダの形で表します。 設計中のシステムと利用者や外部システムとのやりとりを記述します。 詳細は示されていませんが、ユースケース、アクター、システム間の関係の一部が含まれています。 ユースケース図には基本的に4つの要素を含める必要があります。 アクター、システム、ユースケース、そして関係です。 アクターとはシステムを操作、利用する人を表します。 これは、操作がどのように実行されるかを詳述する相互作用図です。 ユースケースを経て時系列的に構造化されたイベントフローを表すために多用されます。 また、オブジェクト間の通信関係を表示します。 シーケンス図にはライフライン、メッセージ、活性化、オブジェクトなどの要素が含まれています。 特定のタスクを実行するために共同作業するオブジェクト間の関係を視覚化し、複雑な操作のための実装ロジックをモデル化するために使用されます。 コラボレーション図は相互作用図の1つで、コミュニケーションとも呼ばれます。 オブジェクト、マルチオブジェクト、アクター、アソシエーションの役割、委任、自己へのリンク、制約とノートで構成されています。 これは、サービスを提供するためのアクティビティの調整方法をモデル化したり、複数の操作を達成するために必要なイベントを表示したり、単一のユースケースのイベントがどのように相互に関連しているかを示したりするために使用されます。 アクティビティ図はアクティビティ、状態、アクティビティと状態間の遷移から構成されます。 イベントが発生したときにオブジェクトすべての可能な状態を記述します。 そのため、この最も重要な目的は、オブジェクト動作の開始から終了までのライフタイムをモデル化することです。 ステートチャート図には状態、初期状態、最終状態、遷移など要素が含まれています。 システム開発設計書を書く際には、事前にそのモデリングの目的を考え、その目標に応じて適切なUML図を選択することがお勧めです。 早速UMLモデリングツールを以下よりダウンロードし、すべてのUML図を実際に見てみましょう。
次の