振る舞いに関するデザインパターン
概要
state = ”状態”
状態がよく変わる処理を管理しやすくするデザインパターン
クラス図
登場するクラス
- 抽象クラス(State)
- 状態を表すクラスA(ConcreteStateA)
- 抽象クラスを継承
- 抽象クラスのメソッドをオーバーライド
- 状態を表すクラスB(ConcreteStateB)
- 抽象クラスを継承
- 抽象クラスのメソッドをオーバーライド
- 現在の状態を保持するクラス(Context)
どういう時に使う?
main(contoroller)の処理で状態に応じてif文の分岐が多岐にわたる場合。
メリット
状態がよく変わるプログラムを管理しやすくなる。
コード例
天気(状態)によって、処理を変える場合のプログラム
天気を状態。
あいさつは処理とした場合の例
ダメなコード例
#!/usr/bin/ruby
class Weather
# 天気の状態を保持する
# 雨ならRainy
def initialize(weather)
@weather = weather
end
def ice_break
if @weather == "Sunny"
puts @weather
puts "今日は晴れて、良い天気ですねー!!!"
elsif @weather == "Rainy"
puts "今日は雨がザーザーですね。"
end
end
def choose_fastion
if @weather == "Sunny"
puts "なのでスニーカーを履こう"
elsif @weather == "Rainy"
puts "なので長靴を履こう"
end
end
def switch_weather(weather)
@weather = weather
end
end
obj = Weather.new("Sunny")
obj.ice_break
obj.choose_fastion
puts "------" * 5
obj.switch_weather("Rainy")
obj.ice_break
obj.choose_fastion
よくないところ
新しく状態を加える(例えば曇りを足す)場合、if文の分岐を全て見直さないといけない。ここでいうice_breakとchoose_fastionの中のif文。
Stateパターン
#!/usr/bin/ruby
# State Pattern
# 抽象クラス
class State
def ice_break
# 実装されていなかったら例外を出す
raise "not implemented error."
end
def choose_fastion
# 実装されていなかったら例外を出す
raise "not implemented error."
end
end
class SunnyDay < State
def ice_break
puts "今日は晴れて、良い天気ですねー!!!"
end
def choose_fastion
puts "なのでスニーカーを履こう"
end
end
class RainyDay < State
def ice_break
puts "今日は雨がザーザーですね!"
end
def choose_fastion
puts "なので長靴を履こう"
end
end
class CloudyDay < State
def ice_break
puts "今日は天気悪いんですかねー..."
end
def choose_fastion
puts "なのでなんでもよい"
end
end
# 状況を保持するクラス
class Context
def initialize
@sunny = SunnyDay.new
@rainy = RainyDay.new
@cloudy = CloudyDay.new
# 状況を保持
@state = @sunny
end
def change_state(weather)
if weather == "SunnyDay"
@state = @sunny
elsif weather == "RainyDay"
@state = @rainy
else
@state = @cloudy
end
end
def ice_break
puts @state.class
@state.ice_break
end
def choose_fastion
@state.choose_fastion
end
end
# Client(main)
obj = Context.new
obj.ice_break
obj.choose_fastion
puts "------" * 5
obj.change_state("RainyDay")
obj.ice_break
obj.choose_fastion
puts "------" * 5
obj.change_state("CloudyDay")
obj.ice_break
obj.choose_fastion