Help us understand the problem. What is going on with this article?

Stateパターン

More than 3 years have passed since last update.

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

概要

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

参考

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした