カテゴリ: Ruby 更新日: 2026/04/04

Rubyで状態遷移をマスター!状態機械の基礎と実装パターンを初心者向けに徹底解説

状態遷移を制御構造で表す:状態機械の基礎と実装パターン
状態遷移を制御構造で表す:状態機械の基礎と実装パターン

先生と生徒の会話形式で理解しよう

生徒

「Rubyで信号機やゲームのキャラクターのように、状況によって動きが変わる仕組みを作るにはどうすればいいですか?」

先生

「それは『状態遷移(じょうたいせんい)』という考え方を使うのが一番です。プログラミングでは、今の状態をしっかりと管理することがとても大切なんですよ。」

生徒

「今の状態……。例えば、信号が『赤』なら『止まる』、『青』なら『進む』といった感じでしょうか?」

先生

「その通りです!それをスマートにプログラムで表現する『状態機械(ステートマシン)』の基礎を、簡単な例えで学んでいきましょう!」

1. 状態遷移とは?今の状況でルールが変わる仕組み

1. 状態遷移とは?今の状況でルールが変わる仕組み
1. 状態遷移とは?今の状況でルールが変わる仕組み

Rubyのプログラムにおいて、状態遷移(じょうたいせんい)とは、あるモノの「今の状態」が、何かのきっかけで「次の状態」に変化することを指します。パソコンを触ったことがない方でも、身近なもので想像してみると分かりやすくなります。

例えば、スマートフォンの画面を考えてみましょう。「スリープ状態」のときにボタンを押すと「ロック画面」になり、パスワードを入れると「ホーム画面」に変わりますよね。このように、一つのモノが複数の顔を持ち、ルールに従って変化していく様子を管理するのが状態遷移の役割です。

プログラミングでこの仕組みを正しく作れるようになると、複雑なアプリやゲームを作っても「今、何が起きているのか」が整理され、間違いの少ないしっかりとしたシステムを作ることができるようになります。

Rubyの文法を基礎からしっかり固めたい人や、 現場で役立つ「テスト駆動開発」の考え方まで身につけたい人には、 評価の高いこの一冊がおすすめです。

プロを目指す人のためのRuby入門をAmazonで見る

※ Amazon広告リンク

2. 状態機械(ステートマシン)という考え方

2. 状態機械(ステートマシン)という考え方
2. 状態機械(ステートマシン)という考え方

少し難しい名前ですが、状態機械(じょうたいきかい)、またはステートマシンという言葉があります。これは「今の状態」と「起きる出来事(イベント)」、そして「次にどうなるか」をセットにして考える設計図のようなものです。

状態機械を設計するときは、以下の3つのポイントを意識します。

  • 状態(ステート): 「待機中」「実行中」「停止中」などの現在の様子。
  • 出来事(イベント): 「ボタンが押された」「時間が経過した」などのきっかけ。
  • 遷移(せんい): Aの状態からBの状態へ移り変わること。

これらをRubyのコードに落とし込むことで、バラバラだった条件分岐が一つにまとまり、とても読みやすいプログラムになります。

3. case文を使った基本的な実装パターン

3. case文を使った基本的な実装パターン
3. case文を使った基本的な実装パターン

状態を管理するとき、Rubyで最も相性が良いのがcase文です。if文をたくさん並べるよりも、「今の状態は何かな?」と一つずつ確認していく作業がとてもスッキリと書けます。

まずは、信号機の変化をシミュレーションする簡単なコードを見てみましょう。


# 現在の信号の状態を決める
current_state = "青"

# 今の状態によって、次の状態が何になるかを決める
next_state = case current_state
             when "青"
               "黄"
             when "黄"
               "赤"
             when "赤"
               "青"
             else
               "故障中"
             end

puts "今の信号は#{current_state}です。次は#{next_state}に変わります。"

実行結果は以下のようになります。


今の信号は青です。次は黄に変わります。

このように、今の状態をチェックして次に繋げるのが、状態遷移制御の第一歩です。

4. 状態を「変数」に入れて変化を記録しよう

4. 状態を「変数」に入れて変化を記録しよう
4. 状態を「変数」に入れて変化を記録しよう

プログラムを動かし続けるためには、今の状態を変数(へんすう)という箱に入れて、常に上書きしていく必要があります。変数とは、データを入れておく名前付きの箱のことです。

次に、ゲームのキャラクターの「冒険」を例にしたコードを書いてみます。ボタンを押すごとに「休息」「探索」「戦闘」と切り替わるイメージです。


# 最初は「休息」からスタート
status = "休息"

# 3回行動してみる
3.times do |i|
  puts "#{i+1}回目の行動:今は【#{status}】です"
  
  case status
  when "休息"
    status = "探索"
    puts "体力が回復したので、森へ出かけます。"
  when "探索"
    status = "戦闘"
    puts "モンスターに出会いました!"
  when "戦闘"
    status = "休息"
    puts "戦いに勝利したので、キャンプに戻ります。"
  end
  puts "------------------------"
end

このコードでは、一回の行動が終わるたびに変数の中身を書き換えています。これにより、同じ処理を繰り返しているのに、毎回違うドラマが生まれるようになるのです。

5. 不正な遷移を防ぐ「バリデーション」の重要性

5. 不正な遷移を防ぐ「バリデーション」の重要性
5. 不正な遷移を防ぐ「バリデーション」の重要性

状態遷移を作るときに最も気をつけなければならないのが、「ありえない変化」を防ぐことです。

例えば、銀行のアプリで「未ログイン」の状態からいきなり「送金完了」の状態に飛んでしまったら大変ですよね。プログラミング未経験の方が陥りやすいミスは、どこからでもどんな状態に変えられるようにしてしまうことです。

これを防ぐために、変化させても良いかどうかをチェックする仕組みを入れます。これをバリデーション(妥当性の確認)と呼びます。「もし今の状態がAのときだけ、Bに変えてもいいよ」という制限をかけることが、安全なアプリ作りのコツです。

6. メソッドを使って遷移のルールをカプセル化する

6. メソッドを使って遷移のルールをカプセル化する
6. メソッドを使って遷移のルールをカプセル化する

プログラムが大きくなってくると、あちこちに状態を書き換えるコードを書くのは危険です。そこで、状態を変えるための専用の窓口(メソッド)を作ります。

メソッドとは、複数の処理を一つにまとめて名前を付けたものです。これを専門用語でカプセル化と呼びます。中身を隠して、決められたルールでしか操作できないようにするのです。


# お風呂の給湯器の状態を管理する仕組み
@bath_status = "空"

def push_button
  case @bath_status
  when "空"
    @bath_status = "お湯をためる"
    puts "お湯を入れ始めました。"
  when "お湯をためる"
    @bath_status = "満タン"
    puts "お風呂が沸きました!"
  when "満タン"
    @bath_status = "空"
    puts "お湯を捨てました。"
  end
end

# ボタンを順番に押してみる
push_button
push_button
push_button

こうすることで、お風呂が「空」なのにいきなり「満タン」になるようなバグ(プログラムの間違い)を防ぐことができます。

7. 状態ごとに処理を切り分けるメリット

7. 状態ごとに処理を切り分けるメリット
7. 状態ごとに処理を切り分けるメリット

状態遷移の考え方を取り入れる最大のメリットは、「今の状態に関係ないコードを無視できる」という点にあります。

もし、すべての条件を一気に考えようとすると、頭がパンクしてしまいます。しかし、「今は『お湯をためる』状態のことだけ考えればいいんだ」と集中できれば、開発はぐっと楽になります。

また、新しい状態(例えば「保温中」など)を追加したくなったときも、case文の中に新しい一行を足すだけで済むことが多いです。このように、後から機能を追加しやすいことを拡張性(かくちょうせい)が高いと言います。

8. 複雑な遷移図をコードに落とし込むコツ

8. 複雑な遷移図をコードに落とし込むコツ
8. 複雑な遷移図をコードに落とし込むコツ

いきなりコードを書き始めるのではなく、まずは紙とペンで丸と矢印を書いてみるのがプロのやり方です。丸の中に「状態」を書き、矢印の上に「きっかけ」を書きます。

この図を状態遷移図と呼びます。図が完成すれば、あとはその矢印を一つずつcase文やif文に書き換えていくだけです。

パソコンの操作に慣れていない方でも、この「図を書く」という作業なら取り組みやすいはずです。論理的に考える力を養うには、実はタイピングよりもこうした準備運動の方が大切だったりします。

9. 実践的なクラス設計での管理

9. 実践的なクラス設計での管理
9. 実践的なクラス設計での管理

最後に、本格的なプログラムでよく使われるクラスを使った管理方法を少しだけ覗いてみましょう。


class Door
  def initialize
    @state = "閉まっている"
  end

  def open
    if @state == "閉まっている"
      @state = "開いている"
      puts "ドアを開けました。"
    else
      puts "ドアはすでに開いています。"
    end
  end

  def close
    if @state == "開いている"
      @state = "閉まっている"
      puts "ドアを閉めました。"
    else
      puts "ドアはすでに閉まっています。"
    end
  end
end

my_door = Door.new
my_door.open
my_door.open # 二回目は「すでに開いている」と出る

このように、モノ(ドア)の中に自分の状態を持たせることで、より人間に理解しやすい直感的なプログラムになります。

10. 状態遷移を使いこなしてプログラミングを楽しもう

10. 状態遷移を使いこなしてプログラミングを楽しもう
10. 状態遷移を使いこなしてプログラミングを楽しもう

状態遷移と聞くと難しく感じるかもしれませんが、その本質は「今、何をしているところかな?」という優しい問いかけにあります。

一つ一つの状態を丁寧に定義し、それらが綺麗に移り変わる仕組みが作れるようになると、あなたのプログラムはまるで生きているかのように動き出します。Rubyは、こうした論理的な組み立てをサポートしてくれる強力な機能がたくさん詰まった言語です。

今日学んだ基礎を大切にして、ぜひ身近なものの仕組みをRubyで表現してみてください。自動販売機、電子レンジ、信号機……。周りを見渡せば、状態遷移のヒントはあちこちに転がっていますよ!

関連記事:
カテゴリの一覧へ
新着記事
New1
Ruby
プロキシ環境でも安心!社内ネットワーク下でのRuby gemインストール完全ガイド【SSL対応も解説】
New2
Ruby
Rubyのリテラル総まとめ!初心者でもわかる数値・文字列・配列・ハッシュ・正規表現・範囲
New3
Rails
Railsのimportmap入門|Node不要でJavaScriptを使う方法と落とし穴をやさしく解説
New4
Ruby
OpenSSL関連エラーの直し方を完全解説!証明書・ビルドオプション・brew対策まとめ
人気記事
No.1
Java&Spring記事人気No1
データベース
SQLで複数テーブルを結合する方法を徹底解説!初心者でも図解でわかるJOINと集計の基本
No.2
Java&Spring記事人気No2
Ruby
WindowsでRubyをインストールする方法!RubyInstallerとMSYS2を使った完全ガイド
No.3
Java&Spring記事人気No3
Rails
Hotwire超入門:Turbo Drive / Turbo Frames / Turbo Streams を一気に理解【Rails 7 / Rails 8】
No.4
Java&Spring記事人気No4
データベース
PostgreSQLが遅い原因を解決!初心者向けデータベースチューニングと高速化の基本
No.5
Java&Spring記事人気No5
Rails
Rails 7/8対応|RSpec入門:describe・context・it・expectを初心者向けに完全解説
No.6
Java&Spring記事人気No6
Ruby
Rubyの条件分岐をスッキリ!早期リターンとガード節で読みやすいコードへ
No.7
Java&Spring記事人気No7
データベース
データベース設計の要!外部キー(Foreign Key)とは?初心者向けに徹底解説
No.8
Java&Spring記事人気No8
Ruby
Ruby配列の抽出と条件処理を完全解説!select・reject・take・dropの定番パターン