State - shoonie/StudyingDesignPattern GitHub Wiki

Intent

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

Diagram

disgram

Consequences

  1. It localizes state-specific behavior and partitions behavior for different states.
  2. It makes state transitions explicit.
  3. State objects can be shared.

Implementation

  1. Who defines the state transitions?
  2. A table-based alternative.
  3. Creating and destroying State objects.
  4. Using dynamic inheritance.

Sample Code

//https://www.robertlarsononline.com/2017/05/11/state-pattern-using-cplusplus/
#include <iostream>
namespace MusicPlayerSample
{
	enum State
	{
		ST_STOPPED,
		ST_PLAYING,
		ST_PAUSED
	};
	class AbstractMusicPlayer {
	public:
		virtual void  SetState(State state) = 0;
	};

	class MusicPlayerState {
	public:
		MusicPlayerState(std::string name) : m_name(name)
		{
		}
		virtual ~MusicPlayerState() {}

		virtual void Play(AbstractMusicPlayer * player) {
			std::cout << "Illegal state transition from " 
                                  << GetName() << " to Playing\n";
		}
		virtual void Pause(AbstractMusicPlayer * player) {
			std::cout << "Illegal state transition from " 
                                  << GetName() << " to Paused\n";
		}
		virtual void Stop(AbstractMusicPlayer * player) {
			std::cout << "Illegal state transition from " 
                                  << GetName() << " to Stopped\n";
		}

		std::string GetName() { return m_name; }

	private:
		std::string   m_name;
	};

	class PlayingState : public MusicPlayerState {
	public:
		PlayingState() : MusicPlayerState(std::string("Playing"))
		{
		}
		virtual ~PlayingState() {}

		virtual void Pause(AbstractMusicPlayer * player) {
			player->SetState(ST_PAUSED);
		}
		virtual void Stop(AbstractMusicPlayer * player) {
			player->SetState(ST_STOPPED);
		}
	};



	class PausedState : public MusicPlayerState {
	public:
		PausedState() : MusicPlayerState(std::string("Paused"))
		{
		}
		virtual ~PausedState()
		{}

		virtual void Play(AbstractMusicPlayer * player)
		{
			player->SetState(ST_PLAYING);
		}
		virtual void Stop(AbstractMusicPlayer * player)
		{
			player->SetState(ST_STOPPED);
		}
	};

	class StoppedState : public MusicPlayerState {
	public:
		StoppedState() : MusicPlayerState(std::string("Stopped"))
		{
		}

		virtual ~StoppedState() {}

		virtual void Play(AbstractMusicPlayer * player) {
			player->SetState(ST_PLAYING);
		}
	};

	class MusicPlayer :public AbstractMusicPlayer
	{
	public:
		MusicPlayer() : m_pState(new StoppedState())
		{}
		virtual ~MusicPlayer() {
			if (m_pState != nullptr)
				delete m_pState;
		}

		void Play() {
			m_pState->Play(this);
		}
		void Pause() {
			m_pState->Pause(this);
		}
		void Stop() {
			m_pState->Stop(this);
		}
		void SetState(State state);

	private:
		MusicPlayerState * m_pState;
	};


	void MusicPlayer::SetState(State state)
	{
		std::cout << "changing from " << m_pState->GetName() << " to ";
		delete m_pState;

		if (state == ST_STOPPED)
		{
			m_pState = new StoppedState();
		}
		else if (state == ST_PLAYING)
		{
			m_pState = new PlayingState();
		}
		else
		{
			m_pState = new PausedState();
		}

		std::cout << m_pState->GetName() << " state\n";
	}
}
int main()
{
	MusicPlayerSample::MusicPlayer player;

	player.Play();
	player.Pause();
	player.Stop();

	return 0;
}
⚠️ **GitHub.com Fallback** ⚠️