Skip to content
Shawn Chung edited this page Jul 27, 2018 · 2 revisions

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;
}

Clone this wiki locally