1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【GoFデザインパターン】State(ステート)パターンをJavaで理解する

1
Last updated at Posted at 2026-09-29

はじめに

本記事は、GoFデザインパターン解説シリーズの1つです。

今回は、振る舞いに関するパターンの中のState(ステート)パターンを解説します。

「オブジェクトの内部状態によって振る舞いが変わる」処理を、スッキリ整理するためのパターンです。

解決したい課題

「オブジェクトの状態によって、同じ操作でも振る舞いが変わる」処理を、素朴に実装しようとすると、巨大なif文やswitch文で状態ごとの分岐を書くことになりがちです。

例えば、自動販売機を考えます。

「お金投入前」「お金投入済み」「売り切れ」という状態によって、「商品ボタンを押す」という同じ操作の結果が変わります。

これを1つのクラスの中でswitch(state)のように分岐すると、状態が増えるたびにすべてのメソッドのswitch文に新しい分岐を追加しなければならず、修正漏れのリスクも高まり、コードも急速に肥大化していきます。

Stateパターンは、「状態」自体を1つのオブジェクトとして切り出し、状態ごとに振る舞いを持つクラスに分離することで、この問題を解決します。

image.png

クラス構成

  • Context(コンテキスト): 現在の状態(State)への参照を持ち、状態に応じた処理を状態オブジェクトに委譲するクラス
  • State(ステート): 状態ごとの振る舞いを定義する、共通インターフェース
  • ConcreteState(具体的なステート): 特定の状態における、具体的な振る舞いを実装するクラス

image.png

Javaでの実装例

自動販売機を例に実装してみます。

State:共通インターフェース

public interface VendingMachineState {
    void insertCoin(VendingMachine machine);
    void selectProduct(VendingMachine machine);
}

Context:自動販売機本体

public class VendingMachine {
    // 現在の状態への参照。状態が切り替わるとこのフィールドが差し替わる
    private VendingMachineState state;

    public VendingMachine() {
        this.state = new NoCoinState(); // 初期状態: お金投入前
    }

    public void setState(VendingMachineState state) {
        this.state = state;
    }

    // Context自身は「何をすべきか」を判断せず、現在の状態オブジェクトに処理を委譲する
    public void insertCoin() {
        state.insertCoin(this);
    }

    public void selectProduct() {
        state.selectProduct(this);
    }
}

ConcreteState:状態ごとの具体的な振る舞い

public class NoCoinState implements VendingMachineState {
    @Override
    public void insertCoin(VendingMachine machine) {
        System.out.println("[お金投入前] コインを受け付けました");
        machine.setState(new HasCoinState()); // 「お金投入済み」状態へ遷移
    }

    @Override
    public void selectProduct(VendingMachine machine) {
        System.out.println("[お金投入前] お金が投入されていません");
    }
}

public class HasCoinState implements VendingMachineState {
    @Override
    public void insertCoin(VendingMachine machine) {
        System.out.println("[お金投入済み] すでにコインが投入されています");
    }

    @Override
    public void selectProduct(VendingMachine machine) {
        System.out.println("[お金投入済み] 商品を排出しました");
        machine.setState(new SoldOutState()); // 在庫がなくなった想定で「売り切れ」状態へ遷移
    }
}

public class SoldOutState implements VendingMachineState {
    @Override
    public void insertCoin(VendingMachine machine) {
        System.out.println("[売り切れ] 只今売り切れ中です。コインを返却します");
    }

    @Override
    public void selectProduct(VendingMachine machine) {
        System.out.println("[売り切れ] 商品がありません");
    }
}

利用側のコード

public class Main {
    public static void main(String[] args) {
        VendingMachine machine = new VendingMachine();

        machine.selectProduct(); // お金投入前に選択 → 拒否される
        machine.insertCoin();    // コイン投入 → 状態が変わる
        machine.selectProduct(); // 商品選択 → 排出され、売り切れ状態になる
        machine.insertCoin();    // 売り切れ状態でコイン投入 → 返却される
    }
}

実行結果:

[お金投入前] お金が投入されていません
[お金投入前] コインを受け付けました
[お金投入済み] 商品を排出しました
[売り切れ] 只今売り切れ中です。コインを返却します

image.png

VendingMachine(Context)自身は、if文やswitch文による状態判定を一切行っていません。

「現在の状態オブジェクトに処理を委譲する」だけです。状態ごとの振る舞いは、それぞれ独立したNoCoinState・HasCoinState・SoldOutStateクラスに分かれており、新しい状態(例えば「メンテナンス中」)を追加したい場合も、新しいクラスを1つ追加するだけで対応でき、既存の状態クラスには一切手を入れる必要がありません。

Strategyパターンとの違い

Stateパターンは、クラス構造だけを見ると次回解説するStrategyパターンと非常によく似ています(どちらも「振る舞いをオブジェクトとして切り出し、委譲する」構造です)。

違いは意図と状態遷移の有無にあります。

Strategyは「アルゴリズムを外部から選んで注入する」ことが目的で、通常は実行中に自動的に切り替わることを想定しません。

一方Stateは、「オブジェクト自身の内部状態に応じて振る舞いが変わり、かつ状態自身が次の状態への遷移を引き起こす」ことを想定しています。

上記の例で、各State実装クラスがmachine.setState(...)を呼んで自ら次の状態への遷移を行っている点が、この違いを表しています。

使用場面

  • 自動販売機、信号機、注文のステータス管理(未処理→処理中→発送済み→完了)など、明確な状態遷移を持つ処理
  • 同じ操作(メソッド)でも、オブジェクトの状態によって振る舞いが大きく異なる場合
  • 巨大なif/switchによる状態分岐が、あちこちのメソッドに散らばってしまっている場合の整理
  • ゲームにおけるキャラクターの状態(通常・攻撃中・スタン中など)の管理

まとめ

項目 内容
解決する課題 オブジェクトの状態によって振る舞いが変わる処理が、巨大なif/switch文になってしまう
実現方法 状態ごとの振る舞いを、それぞれ独立したStateクラスに切り出す
メリット 新しい状態の追加が、既存コードを変更せずに新クラスの追加だけで済む
Strategyとの違い Stateは状態遷移を伴う自己駆動、Strategyは外部からアルゴリズムを選んで注入する

おすすめ書籍

GoFの23パターンをより深く学びたい方には、以下の書籍がおすすめです。
Java言語のサンプルコードとUMLを使い、初心者にもわかりやすく解説されています。

Java言語で学ぶデザインパターン入門 第3版 [ 結城 浩 ]

※本リンクはアフィリエイトリンクを含みます。

参考

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?