add example of state pattern in C++
This commit is contained in:
parent
d7a25a0efc
commit
1c78867d91
|
@ -21,3 +21,4 @@ add_subdirectory(bridge)
|
|||
add_subdirectory(factory)
|
||||
add_subdirectory(prototype)
|
||||
add_subdirectory(abstract-factory)
|
||||
add_subdirectory(state)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
###############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
|
||||
## About: A project for practicing the state C++ design pattern ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################
|
||||
#
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(
|
||||
#[[NAME]] State
|
||||
VERSION 1.0
|
||||
DESCRIPTION "An example of the state design pattern in C++"
|
||||
LANGUAGES CXX
|
||||
)
|
||||
add_compile_options("-Wall")
|
||||
|
||||
add_library(state "state.cpp")
|
||||
add_executable(state-test "main.cpp")
|
||||
target_link_libraries(state-test state)
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include "state.hpp"
|
||||
|
||||
int main(const int argc, const char * argv[]) {
|
||||
Car * testCar = new Car;
|
||||
testCar->report();
|
||||
|
||||
// Test transition from Stopped->Running
|
||||
testCar->Start();
|
||||
testCar->report();
|
||||
|
||||
// Test transition from Running->Stopped
|
||||
testCar->Stop();
|
||||
testCar->report();
|
||||
|
||||
// Test transition from Stopped->Broken
|
||||
testCar->Smash();
|
||||
testCar->report();
|
||||
|
||||
std::cout << "\nTesting burning state...\n";
|
||||
|
||||
Car *newCar = new Car;
|
||||
newCar->report();
|
||||
|
||||
// Test transition from Stopped->Running->Burning
|
||||
newCar->Start();
|
||||
newCar->Smash();
|
||||
newCar->report();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
#include "state.hpp"
|
||||
|
||||
// Delegate calls from State->changeState to Car->changeState
|
||||
void State::changeState(Car *c, State *s) { c->changeState(s);}
|
||||
|
||||
// Stopped state transitions
|
||||
void Stopped::Start(Car *c) { changeState(c, Running::instance());}
|
||||
void Stopped::Smash(Car *c) { changeState(c, Broken::instance());}
|
||||
|
||||
// Running state transitions
|
||||
void Running::Stop(Car *c) { changeState(c, Stopped::instance());}
|
||||
void Running::Smash(Car *c) { changeState(c, Burning::instance());}
|
|
@ -0,0 +1,147 @@
|
|||
|
||||
#ifndef STATE_HPP
|
||||
#define STATE_HPP
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "state.hpp"
|
||||
|
||||
class Car;
|
||||
|
||||
// State base class
|
||||
class State {
|
||||
public:
|
||||
State() = default;
|
||||
~State() = default;
|
||||
|
||||
// Calls c->changeState(s)
|
||||
void changeState(Car *c, State *s);
|
||||
|
||||
// Virtual state transition functions
|
||||
// + By default, nothing happens; Derived States can override if needed
|
||||
virtual void Start(Car *c) {}
|
||||
virtual void Stop(Car *c) {}
|
||||
virtual void Smash(Car *c) {}
|
||||
virtual std::string report() = 0;
|
||||
|
||||
private:
|
||||
State(const State &) = default;
|
||||
State &operator=(const State&) { return *this;}
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// Derived State: Stopped
|
||||
class Stopped : public State {
|
||||
public:
|
||||
static State *instance()
|
||||
{
|
||||
// For all derived states, there only needs to be a single instance
|
||||
// + Use singleton pattern to prevent duplicate states
|
||||
// + A single instance of a state can be applied to N cars
|
||||
static State *oneInstance = new Stopped;
|
||||
return oneInstance;
|
||||
}
|
||||
|
||||
// State transitions valid for this state
|
||||
void Start(Car *c) override;
|
||||
void Smash(Car *c) override;
|
||||
|
||||
std::string report() override { return "Stopped";}
|
||||
|
||||
private:
|
||||
Stopped() = default;
|
||||
~Stopped() = default;
|
||||
Stopped(const Stopped &) = default;
|
||||
Stopped &operator=(const Stopped &) { return *this;}
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// Derived State: Running
|
||||
class Running : public State {
|
||||
public:
|
||||
static State *instance()
|
||||
{
|
||||
static State *oneInstance = new Running;
|
||||
return oneInstance;
|
||||
}
|
||||
|
||||
// State transitions valid for this state
|
||||
void Stop(Car *c) override;
|
||||
void Smash(Car *c) override;
|
||||
|
||||
std::string report() override { return "Running";}
|
||||
|
||||
private:
|
||||
Running() = default;
|
||||
~Running() = default;
|
||||
Running(const Running &) = default;
|
||||
Running &operator=(const Running &) { return *this;}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
// Derived State: Burning
|
||||
class Burning : public State {
|
||||
public:
|
||||
static State *instance()
|
||||
{
|
||||
static State *oneInstance = new Burning;
|
||||
return oneInstance;
|
||||
}
|
||||
|
||||
// No state transitions possible; The car is burning.
|
||||
|
||||
std::string report() override { return "Burning";}
|
||||
|
||||
private:
|
||||
Burning() = default;
|
||||
~Burning() = default;
|
||||
Burning(const Burning &) = default;
|
||||
Burning &operator=(const Burning &) { return *this;}
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
// Derived State: Broken
|
||||
class Broken : public State {
|
||||
public:
|
||||
static State *instance()
|
||||
{
|
||||
static State *oneInstance = new Broken;
|
||||
return oneInstance;
|
||||
}
|
||||
|
||||
// No state transitions possible; The car is broken.
|
||||
|
||||
std::string report() override { return "Broken";}
|
||||
|
||||
private:
|
||||
Broken() = default;
|
||||
~Broken() = default;
|
||||
Broken(const Broken &) = default;
|
||||
Broken &operator=(const Broken &) { return *this;}
|
||||
};
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
// Car controlled by current State
|
||||
class Car {
|
||||
public:
|
||||
Car() {state = Stopped::instance();}
|
||||
~Car() = default;
|
||||
|
||||
void report() const { std::cout << "State: " << state->report() << std::endl;}
|
||||
|
||||
// Delegate calls to state transitions relative to that current state
|
||||
virtual void Start() { state->Start(this);}
|
||||
virtual void Stop() { state->Stop(this);}
|
||||
virtual void Smash() { state->Smash(this);}
|
||||
|
||||
void changeState(State *s) { state = s;}
|
||||
|
||||
private:
|
||||
State *state;
|
||||
};
|
||||
|
||||
#endif // STATE_HPP
|
Loading…
Reference in New Issue