【GoFデザインパターン】Stateパターンを図解で説明

状態を管理するStateパターン
ぎゅう

StoreパターンとStateパターンって、
どう違うの?

Storeパターンを学習して思ったことは、「Stateパターンとどう違うの?」ということでした。

そこで今回Stateパターンに興味を持ち学習することにしました

参考書籍ですが、「Java言語で学ぶ デザインパターン入門」です

まずはソースコードをダウンロードしました。

ぎゅう

おおおおおお!!
各デザインパターンのディレクトリ見れて良きです

やはり書籍もいいですが、コードエディター上で実際のコードを見るのが一番理解に繋がる気がします。

コードジャンプと検索を繰り返して、構造を理解していきます。

目次

そもそもなぜStateパターンが誕生したのか?

これ面白いのが、時間や季節などモノではない“状態”もオブジェクト思考だとclass化しないといけないってことです。

昼と夜という“状況”を定義するとして、それを実現するために太陽や地球のclassを作るのもちょっと違いますよね

ぎゅう

確かにそうだ…。
太陽とか壮大すぎ….。

オブジェクト思考は素晴らしいですが、“モノ”ではなくて“状況・状態”でしか表現できないものもあるよね。

じゃあ、状況・状態を表現するには、どうすればよいでしょうか?

その解決策として、Stateパターンが誕生したということです。

ぎゅう

なるほど!!これは面白そうだ

なぜStateパターンがいいのか?そのメリット

Stateパターンを使う、使わないでどういった違いが生まれるのか?

何回もif文を書くか、1回のif文で完結させるか。

上記の違いが生まれます。

結論をいうと、下記になります。

  • Stateパターンを使わない場合:if文がたくさん必要。
  • Stateパターンを使う場合:1回のif文で完結する

具体的に違いをみてみましょう!

擬似コーディングで比較する

Stateパターンを使わない場合,if文が多くなる。

<?php

class お店 
{
    /**
     * お店が空いているか尋ねる。
     *
     * @return string
     */
    public function isOpened(): string
    {
        if(昼) {
            echo "営業中です";
        } elseif(夜) {
            echo "営業時間外です";
        }
    }

    /**
     * 店員に尋ねる
     *
     * @return string
     */
    public function call(): string
    {
        if(昼) {
            echo "はい、なんでしょうか?";
        } elseif(夜) {
            echo "zzzz。";
        }
    }
}

Stateパターンを使う場合、if文が1回で済む

<?php

class お店 
{
    private State $state;

    /**
     * お店の状況を確認する。
     *
     * @return void
     */
    public function checkState()
    {
        // このif文で完結
        if (昼) {
            $this->state = 開店ステータスクラス;
        } elseif (夜) {
            $this->state = 閉店ステータスクラス;

        }

    }

    /**
     * お店が空いているか尋ねる。
     *
     * @return string
     */
    public function isOpened(): string
    {
        $this->state->isOpened(); // if文が不要
    }

    /**
     * 店員に尋ねる
     *
     * @return string
     */
    public function call(): string
    {
        $this->state->call(); // if文が不要
    }
}

こんな感じになります。

ぎゅう

擬似コーディングじゃない…。

擬似コード書くつもりが、ちょっとPHP混じってしまいました笑

Stateパターンを使わない場合、メソッドごとにif文が必要になります。

Stateパターンを使うと、Stateの切り替え時のみif文を使います。

ぎゅう

if文1回で済むとか最高じゃん

そうですよね。

if文が1回で済むことで、コードがシンプルになりますし、非常に可読性も高まります。

if文でごちゃつかないのは魅力の一つだと思います。

これ考えた人めっちゃ賢いですよね。すごくないですか?

理解を深める

さて、Stateパターンの魅力を理解したところで、クラス設計の理解を深めましょう。

先ほどの擬似コーディングはあくまで魅力を伝えるためのものです。

実際にはクラス分けをして、役割を分担させます。

じゃあ、どうやってClassを分けようか?

という疑問が生まれるはずです。

そこで、Stateパターンのクラス設計を理解していきましょう!

まず状態を表現するクラスの役割ですが、大きくわけると2つあります。

  • 対象の状況
  • 状態

図解で理解しよう

図解でお伝えしていきましょう。

まずは先ほどお伝えした二つのクラスです。

Stateパターンを表現する2つのクラス
Stateパターンを表現する2つのクラス

さらに状態は複数あるので、具体的な状態を追加します。

ConcreteStateを含めたStateパターンの説明
Stateパターンを表現するために、具体的な状態のクラスを追加

この3つが状態を表現するために必須なクラスです。

ぎゅう

ごめん、Contextがわからないです。

そうですよね。Contextはちょっとわかりづらいですよね。

ですが、人で比喩するとわかりやすいですよ

Stateパターンの図解
Stateパターンの図解

人間の場合、感情の状態もあれば、体調の状態もあります。

このように状態といってもグループ分けできますよね。

どの対象についての状態なのか?これを表現するのかContextです。

Contextでメソッドのふるまいを持たせて、Stateの状態によって処理内容が変わる仕組みです。

ぎゅう

超わかりやすい!!

それでは抽象的な概念がわかったところで、よりプログラムに落とし込みます。

EmotionsContextの処理を実行 → 現在の状態であるStateの実装クラスを1つの値を取得・処理を実行

といった関係ですね

これで同じふるまいでも、状態によって変化する面白いプログラムが作れますね

これらを理解した上で書籍を読んでみると、理解度がぐん!と上がるのでおすすめです。

終わりに

ということで、今回stateパターンを学習しました。

Storeパターンは状態を管理するオブジェクトをimportして、値を更新してました。

Stateパターンはさらに詳しいクラス設計で、状態を管理するStateの他にふるまいをもつContextクラスをもつことで、無駄なif文なく処理をつくることができる。

こういう認識です。

書籍の内容をまるごと使うと、ただのコピペですし、著作権的にもよろしくないので、自分なりの理解で書いてみました。

間違い等があれば、ぜひぜひ教えてください。

ぎゅう
WEBエンジニア
渋谷でWEBエンジニアとして働く。
LaravelとVue.jsをよく取り扱い、誰でも仕様が伝わるコードを書くことを得意とする。
先輩だろうがプルリクにコメントをして、リファクタしまくる仕様伝わるコード書くマン
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次
閉じる