##概要
状態を表すオブジェクトを導入することで、オブジェクトの内部状態が変化した時に、オブジェクトが振る舞いを変えるようにするパターン
以下の3種類のクラスからなる
- Contextクラス(クライアントに必要なインターフェイスを定義し、状態を表す3.のインスタンスを保持する)
- Stateクラス(1.の個々の状態に関する振る舞いをカプセル化するためのインターフェイスを定義)
- ConcreteStateクラス(1.のある状態に関する振る舞いを実装)
##具体例と実装
自動空調を例にすると、
上記1~3はそれぞれ
- リモコンクラス(RemoteControllerクラス、空調の運転状態を切り替える)
- 温度調節クラス(TemperatureControlクラス、運転状態に共通の振る舞いを定義)
- 冷房クラス、暖房クラス、エコモードクラス(Coolingクラス、Heatingクラス、EcoModeクラス、冷房、暖房、エコモードそれぞれの運転状態での振る舞いを実装)
が対応する。
コードの詳細は以下
remote_controller.rb
class RemoteController
def initialize(drive_mode)
@drive_mode = drive_mode
end
def drive
@drive_mode.set_temperature
@drive_mode.drive
end
def set_drive_mode(drive_mode)
@drive_mode = drive_mode
end
end
temperature_control.rb
class TemperatureControl
def initialize
@temperature = nil
end
def set_temparature
end
def drive
end
end
cooling.rb
class Cooling < TemperatureControl
def set_temparature
@temperature = 28 # 室温を28度にセット
end
def drive
# 設定温度にしたがって冷房運転を行う
end
end
heating.rb
class Heating < TemperatureControl
def set_temparature
@temperature = 20 # 室温を20度にセット
end
def drive
# 設定温度にしたがって暖房運転を行う
end
end
eco_mode.rb
class EcoMode < TemperatureControl
def drive
# エコモードでの運転を行う
end
end
クライアントコード
# 暑い!
remote_controller = RemoteController.new(Cooling.new)
remote_controller.drive
# 寒い!
remote_controller.set_drive_mode(Heating.new)
remote_controller.drive
##メリット
- 状態毎に振る舞いを分割し、新しい状態や遷移の追加がサブクラスの定義によって簡単に行える
- 複数の状態に対して別々のオブジェクトを用意することで、状態の遷移を明確に表現できる
- ConcreteStateオブジェクトをContextオブジェクトをまたいで共有することでメモリを節約できる
##まとめ
オブジェクト本体と、その状態、振る舞いを表すオブジェクトを別に用意することで、条件分岐をへらし、新しい状態、振る舞いの追加を容易にできるパターン