LoginSignup
18
19

More than 5 years have passed since last update.

Stateパターン

Last updated at Posted at 2016-12-13

振る舞いに関するデザインパターン

概要

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

参考

18
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
19