劇的ビフォ◯アフターで学ぶデザインパターン(state編:after)
前回のソースコードをstateパターンを使用して書き換えていく
前回のソースコードを見てみると、
状態と、その状態の時の振る舞いが描かれていることがわかります。
図の例なら、「HAPPY」「HAPPY時の振る舞い(hello, goodbye)」です。
これを状態クラスとして書き出します。
状態クラス(状態時の振る舞いを持ったクラス)を作成
# たのしい時 class HappyState def self.hello puts 'hello!!!' end def self.goodbye puts 'goodbye!!!' end end
他の2つの状態についても状態クラスとして書き出します。
# 通常 class NormalState def self.hello puts 'hello' end def self.goodbye puts 'goodbye' end end # 風邪引いた時 class ColdState def self.hello puts 'hello...' end def self.goodbye puts 'goodbye...' end end
Humanクラスが状態クラスを持つようにする
そして、Humanクラスでは先ほどの状態クラスをstateとして保持するようにします。
class Human # その人心理的状態 attr_accessor :state def initialize(state = NormalState) # 引数が渡ってきていない場合、デフォルトでNormalStateにする state = state end # 挨拶をさせる(stateクラスにメッセージを送る) def hello state.hello end # 挨拶をさせる(stateクラスにメッセージを送る) def goodbye state.goodbye end # 状態クラスをセットする def set_state(state) state = state end end
if文による条件分岐がなくなり、スッキリしましたね。
Humanクラス使用時
human = Human.new() human.hello human.goodbye human.set_state(ColdState) human.hello human.goodbye human.set_state(HappyState) human.hello human.goodbye
結果
hello goodbye hello... goodbye... hello!!! goodbye!!!
仕様変更
さて、これでstateパターンへの書き換えが終了しました。
ここで例の仕様変更です。
上司「恋に落ちた状態も用意してくれ」
stateパターンを使用しない場合、4行の修正が必要になりました。
stateパターンを使用する場合、既存のソースコードはどのように変更されるでしょうか。
結論
既存のソースコード(Human, ~Stateクラス)は変更されません
新規に以下のクラスが追加されるだけです。
# 恋におちた時 class FallInLoveState def self.hello puts 'hello, love you!' end def self.goodbye puts "Don't leave me alone..." end end
このクラスを使用するときは、先ほどと同じように
human.set_state(FallInLoveState)
human.hello
human.goodbye
とするだけです。
まとめ
stateパターンを使用することにより、オブジェクトの状態をクラスとして分離することが出来ます。
そうすると、新しい状態を追加した際に、既存のソースコードを 一切変更せずに すみ、
新しい状態のクラスを追加するだけですみます。
縮めたのたった4行だけかよ。って思うかもしれません。
たしかにそうです笑
ただ、状態が大量にある場合や複雑な条件分岐が行われる場合、
stateパターンを用いるとソースコードが明快になることが多いです。