【C++でデザインパターン】Stateパターン


はじめに

※注意)
この記事は、私の個人サイト「FumiSite」で投稿した内容の転載です。


現在開発しているプログラムで、
モードによって使用できる機能を分割したいと考えていた時に、
デザインパターンで何かいいのないかなぁっと思って調べた時に出会ったのがこちらの「Stateパターン」でした(∩∀`*)

今回はこの「Stateパターン」について説明を…しません(笑)

その代わりに、私が参考とした記事を紹介します。
その記事がこちら↓

State パターン | TECHSCORE(テックスコア)

そして、

上記の記事はJavaで書かれているのですが、それをC++で実装し直したというのが今回の話です(笑)

どういう内容の話をコーディングしているかは、上記の記事でご確認ください。

まず、これがユーザが呼び出す上位レイヤーの「StatePatternYumichan」クラス。

※由実ちゃんというのは上記のサイトから受け継いでいるだけで、なぜ由実ちゃんなのかは知りません。

StatePatternYumichan.h
#pragma once

#include "OrdinaryState.h"
#include "BadMoodState.h"

class StatePatternYumichan {
public:
    StatePatternYumichan();

/*
*********************************************
* Function
**********************************************
*/
public:
    /*!
    * @brief 朝の挨拶を返す
    * @retuen 朝の挨拶
    */
    std::string morning_greet();

    /*!
    * @brief 防寒対策を返す
    * @retuen 防寒対策
    */
    std::string get_protection_for_cold();

    /*!
    * @brief 風邪をひく
    */
    void has_a_cold();

    /*!
    * @brief 風邪が治る
    */
    void is_over_her_cold();

private:
    /*!
    * @brief ご機嫌を変更する
    */
    void change_state(State * state);

/*
*********************************************
* Variable
**********************************************
*/
private:
    State * state;

};

StatePatternYumichan.cpp
#include "StatePatternYumichan.h"

StatePatternYumichan::StatePatternYumichan() :state(new OrdinaryState) {}

std::string StatePatternYumichan::morning_greet() {
    return this->state->morning_greet();
}

std::string StatePatternYumichan::get_protection_for_cold() {
    return this->state->get_protection_for_cold();
}

void StatePatternYumichan::has_a_cold() {
    this->change_state(new BadMoodState);
}

void StatePatternYumichan::is_over_her_cold() {
    this->change_state(new OrdinaryState);
}

void StatePatternYumichan::change_state(State * state) {
    delete this->state; 
    this->state = state;
}

そして、こちらが由実ちゃんの気分によって受け答えの基底となる「State」クラス。

State.h
#pragma once

#include <string>

/*!
* @brief 由実ちゃんの状態を表す基底クラス
*/
class State {
public:
    /*!
    * @brief 朝の挨拶を返す
    */
    virtual std::string morning_greet() = 0;

    /*!
    * @brief 防寒対策を返す
    */
    virtual std::string get_protection_for_cold() = 0;

};

こちらが通常時の受け答えをする「OrdinaryState」クラス。

OrdinaryState.h
#pragma once
#include "State.h"

class OrdinaryState : public State{
public:
    /*!
    * @brief 朝の挨拶を返す。通常は、男らしく応えます。
    */
    std::string morning_greet() override;

    /*!
    * @brief 防寒対策を返す。通常は、走るようです。
    */
    std::string get_protection_for_cold() override;
};

OrdinaryState.cpp
#include "OrdinaryState.h"

std::string OrdinaryState::morning_greet() {
    return "おっす!";
}

std::string OrdinaryState::get_protection_for_cold() {
    return "走る";
}

こちらが風邪をひいた時の受け答えをする「BadMoodState」クラス。

BadMoodState.h
#pragma once
#include "State.h"

class BadMoodState : public State {
public:
    /*!
    * @brief 朝の挨拶を返す。気分が悪いので、ぶっきらぼうに応えます。
    */
    std::string morning_greet() override;

    /*!
    * @brief 防寒対策を返す。気分が悪いので、ももひきをはきます。
    */
    std::string get_protection_for_cold() override;
};
BadMoodState.cpp
#include "BadMoodState.h"

std::string BadMoodState::morning_greet() {
    return "おお";
}

std::string BadMoodState::get_protection_for_cold() {
    return "ももひき";
}

そして最後に、実際に使用するとしたらこんな感じ。

main.cpp
#include <iostream>
#include "StatePatternYumichan.h"

void comment(const StatePatternYumichan yumicahn){
    std::cout << std::endl;
    std::cout << "  挨拶:";
    std::cout << yumichan.morning_greet() << std::endl;
    std::cout << "防寒方法:";
    std::cout << yumichan. get_protection_for_cold() << std::endl;
}

int main () {
    StatePatternYumichan yumichan;
    // 通常時
    comment(yumichan);

    yumichan.has_a_cold();

    // 風邪をひいて具合が悪い時
    comment(yumichan);

    yumichan.is_over_her_cold();

    // 通常時
    comment(yumichan);
}


GitHubでもプログラムは公開しています。
詳しくは「【C++でデザインパターン】Stateパターン | FumiSite」をご覧ください。