State は、 振る舞いに関するデザインパターンの一つで、 オブジェクトの内部状態が変化した時にその振る舞いを変更することを可能とします。
このパターンは、 状態に関連した振る舞いを個別の状態のクラスへ抽出し、 元のオブジェクトが作業を自分で行わず、 これらのクラスのインスタンスに委任することを強制します。
概念的な例
State デザインパターンを、 自動販売機に適用してみましょう。 話を簡単にするため、 自動販売機は 1 種類の商品しか扱わないこととします。 また、 自動販売機は、 以下の四つの状態のいずれかにあるものと仮定します:
- hasItem (在庫あり)
- noItem (品切れ)
- itemRequested (商品選択済み)
- hasMoney (入金あり)
自動販売機は、 異なるアクションがあります。 簡略化のため、 以下の四つのアクションしかないものとします:
オブジェクトが多くの異なる状態を取ることができ、 入ってくるリクエストに応じてオブジェクトが現在の状態を変更する必要がある場合、 State デザインパターンを使うべきです。
この例では、 自動販売機は、 多くの異なる状態を取ることができ、 状態は常に切り替わります。 自動販売機が、 itemRequested
状態だったとします。 「お金を入れる」 アクションが一旦起きると、 自動販売機は hasMoney
状態に移動します。
現在の状態に応じて、 自動販売機は同じリクエストに対して違う振る舞いをします。 たとえば、 もしユーザーが商品を購入したいとして、 もし hasItemState
状態だったら、 そのまま先に進みますが、 もし noItemState
状態だった場合は、 拒絶します。
この自動販売機のコードは、 ロジックで汚染されていません。 状態依存のコードはすべて、 対応する状態の実装の中にあります。
vendingMachine.go: コンテキスト
state.go: 状態インターフェース
noItemState.go: 具象ステート
hasItemState.go: 具象ステート
itemRequestedState.go: 具象ステート
hasMoneyState.go: 具象ステート
main.go: クライアント・コード
output.txt: 実行結果