Stateパターンとは,オブジェクトの内部状態が変化したときに,処理内容(振る舞い)を変えるパターンである。Stateパターンを使うことによって,オブジェクトの内部状態が増えてもプログラムを容易に変更できるようになり,プログラムの保守性と可読性を高められる。

 例として,さなぎ(Pupa),蝶(Butterfly)へと成長する「芋虫(Caterpillar)」をクラス図で示してみよう。芋虫は成長するにつれ,さなぎ,蝶へと内部状態を変える。それぞれの状態によって,「name()」,「color()」,「move()」というメッセージで名前,色,動きを問いかけたときの処理内容(振る舞い)も変わる。


図1 「Stateパターン」を適用する前後のUMLクラス図
[画像のクリックで拡大表示]

図2 「Stateパターン」を適用する前後のJavaソースコードの例
[画像のクリックで拡大表示]

 例えば芋虫のときは,「name()」というメッセージに対して,「CATERPILLAR」と応答する。さなぎの場合の応答は「PUPAL」である。

 このような要求を満たす芋虫のクラス図は,図1[拡大表示]のように2種類定義できる。左側がパターンを適用していないクラス図,右側がパターンを適用したクラス図である。

 図1の内容はこうだ。「Caterpillar」は状態によって振る舞いを変える。図1左は,Caterpillarを「状態によって振る舞いを変えるオブジェクト」として設計している。図1右は,これにStateパターンを適用して,「振る舞いを持つ複数の状態(CaterpillarState,PupaState,ButterflyState)とリンクを持てるオブジェクト」という設計に変えている。

 このような構造のクラスを定義しておけば,内部状態の数が増減しても,サブクラスを追加・削除するだけで対応できる。その変更は,他のクラスには影響を与えない。

「if文」を排除し保守性を向上

 Stateパターンのカギとなる考え方は,「クラス内に,状態に依存して変化する振る舞いを直接記述しない」ということである。といっても,これだけではまだピンとこない読者もいるだろう。そこで次に,Javaのソースコードを見ながら,状態に依存したオブジェクトの振る舞いの変化をクラス内に直接記述すると,いったい何が問題なのかを説明しよう。

 図2[拡大表示]はStateパターンを適用する前後のソースコードを示している。左が適用前だ。ソースコードには,「Caterpillar」クラスの中に状態を判定する条件分岐(if文)を設けて,1つのメソッドの中で個々の状態に依存した振る舞いを記述している。すなわち,「状態に依存した振る舞いの変化をクラス内に直接記述」している。

 さて,これのいったいどこが問題なのか。プログラミングの経験がある読者は,すでにお分かりだろう。同じ構造の条件分岐が複数存在するため,ある変更を施すと全てのif文で修正が必要となってしまうのである。

 状態に依存したif文を多用すると,プログラムの変更や保守が困難になり,バグの“温床”になりやすい。プログラム内で修正した内容を,if文が登場するすべての個所に反映させなければならないためだ。プログラムの規模が大きくなると,プログラマが修正を忘れることがあるかもしれない。結果としてプログラムの保守性を低下させる危険性がある。

 Stateパターンは,こうした問題に対する解決手段だ。if文を多用したソースコードにStateパターンを適用すると,プログラムの見通しが格段によくなる。その結果,拡張性の高いプログラムを開発できる(図2右)。

適用結果を文書化する習慣を

 デザインパターンの一例として,「Stateパターン」を紹介した。実際にオブジェクト指向開発に携わっていれば,同じような問題にたびたび遭遇していることに気づくだろう。そうやって,問題解決の事例が集まってきたら,それをパターン化して仲間同士で持ち寄り,知識を共有しよう。

 また,実際にパターンを適用したときには,なぜそのパターンを適用したのか,何が問題だったのか,パターン適用によってどのような結果を得ることができたのかを,仕様書にも明記しておこう。そうした習慣を身につけることこそがパターン活用の,そして,オブジェクト指向のエキスパートへの近道となる。


中谷 多哉子/エス・ラグーン社長(和歌山大学客員教授)
1980年東京理科大学理学部応用物理学科卒,1994年筑波大学大学院経営政策科学研究科経営システム科学専攻修了,1998年東京大学大学院総合文化研究科広域化額専攻修了,博士(学術)。日本電子計算,富士ゼロックス情報システムを経て現職