Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

RubyでStateパターン

概要

GoFデザインパターンのStateパターンについて。
状態をクラスで表現します。
状態と処理を分割することでプログラムをよりシンプルにします。

登場人物

State = 状態。状態に依存した振る舞いを表す
ConcreteState = 具象状態
Context = 状況、文脈

UML


実装サンプル

サンプル概要

1日の生活を起床、行動、就寝に分けて出力します。
状態は日にちの種別として、平日と週末の2つにわかれます。
平日は7時に起床、会社で仕事、25時に就寝します。
週末は10時に起床、だらだら過ごす、27時に就寝します。

登場人物

State = DateOfTheWeek :状態。状態に依存した振る舞いを表す
ConcreteState = Weekday : 具象状態
ConcreteState = Weekend : 具象状態
Context = DailyAction : 状況、文脈

UML


サンプルコード

DateOfTheWeek

# encoding: Shift_JIS

=begin rdoc
= DayOfTheWeekクラス
=end
class DayOfTheWeek
  NOT_OVERRRIDE = 'not override error'

  def wake_up()
    raise DayOfTheWeek::NOT_OVERRRIDE
  end

  def act()
    raise DayOfTheWeek::NOT_OVERRRIDE
  end

  def going_to_bed()
    raise DayOfTheWeek::NOT_OVERRRIDE
  end

  def set_date(daily_action, date)
    raise DayOfTheWeek::NOT_OVERRRIDE
  end
end

Weekday

# encoding: Shift_JIS
require_relative './daily_action'
require_relative './day_of_the_week'
require_relative './weekend'

=begin rdoc
= Weekdayクラス
=end
class Weekday < DayOfTheWeek
  def wake_up()
    return "7時"
  end

  def act()
    return "仕事"
  end

  def going_to_bed()
    return "25時"
  end
  
  def set_date(daily_action, date)
    if (date.wday == 0 || date.wday == 6)
      daily_action.change_date Weekend.new
    end
  end
end

Weekend

# encoding: Shift_JIS
require_relative './daily_action'
require_relative './day_of_the_week'
require_relative './weekday'

=begin rdoc
= Weekendクラス
=end
class Weekend < DayOfTheWeek
  def wake_up()
    return "10時"
  end

  def act()
    return "ダラダラ"
  end

  def going_to_bed()
    return "27時"
  end
  
  def set_date(daily_action, date)
    unless (date.wday == 0 || date.wday == 6)
      daily_action.change_date Weekday.new
    end
  end
end

DailyAction

# encoding: Shift_JIS
require_relative './day_of_the_week'
require_relative './weekday'

=begin rdoc
= DailyActionクラス
=end
class DailyAction
  attr_accessor :day_of_the_week

  def initialize()
    @day_of_the_week = Weekday.new
  end

  def wake_up()
    return "#{@day_of_the_week.wake_up}に起きます"
  end

  def act()
    return "#{@day_of_the_week.act}をします"
  end

  def going_to_bed()
    return "#{@day_of_the_week.going_to_bed}に寝ます"
  end

  def set_date(date)
    @day_of_the_week.set_date self,date
  end
  
  def change_date(day_of_the_week)
    @day_of_the_week = day_of_the_week
  end
end

main

# encoding: Shift_JIS
require 'date'
require_relative './daily_action'

daily_action = DailyAction.new
date =  Date.new(2012, 3, 2)
daily_action.set_date(date)
puts daily_action.wake_up 
puts daily_action.act
puts daily_action.going_to_bed
puts "----------------------------------------------"
date =  Date.new(2012, 3, 3)
daily_action.set_date(date)
puts daily_action.wake_up 
puts daily_action.act
puts daily_action.going_to_bed
puts "----------------------------------------------"
date =  Date.new(2012, 3, 4)
daily_action.set_date(date)
puts daily_action.wake_up 
puts daily_action.act
puts daily_action.going_to_bed
puts "----------------------------------------------"
date =  Date.new(2012, 3, 5)
daily_action.set_date(date)
puts daily_action.wake_up 
puts daily_action.act
puts daily_action.going_to_bed
puts "----------------------------------------------"
出力結果
7時に起きます
仕事をします
25時に寝ます
----------------------------------------------
10時に起きます
ダラダラをします
27時に寝ます
----------------------------------------------
10時に起きます
ダラダラをします
27時に寝ます
----------------------------------------------
7時に起きます
仕事をします
25時に寝ます
----------------------------------------------