(C++) State (Design Pattern)
January 25, 2018 · View on GitHub
(C++) State (Design Pattern)
The State is a Design Pattern to 'allow an object to alter its behavior when its internal state changes. The object will appear to change its class' [1]
Below is an example from [2].
Technical facts
Operating system(s) or programming environment(s)
Ubuntu 10.10 (maverick)
Qt Creator 2.0.1
- G++ 4.4.5
Libraries used:
Qt project file: CppDesignPatternState.pro
#------------------------------------------------- # # Project created by QtCreator 2011-04-14T15:44:05 # #------------------------------------------------- QT += core QT -= gui TARGET = CppDesignPatternState CONFIG += console CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp \ gumballmachine.cpp \ hasquarterstate.cpp \ noquarterstate.cpp \ soldoutstate.cpp \ soldstate.cpp HEADERS += \ gumballmachine.h \ hasquarterstate.h \ noquarterstate.h \ state.h \ soldoutstate.h \ soldstate.h
gumballmachine.cpp
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #include <iostream> //--------------------------------------------------------------------------- #include "gumballmachine.h" #include "hasquarterstate.h" #include "noquarterstate.h" #include "soldoutstate.h" #include "soldstate.h" #include "state.h" //--------------------------------------------------------------------------- GumballMachine::GumballMachine(const int n_gumballs) : m_has_quarter_state(new HasQuarterState(this)), m_no_quarter_state(new NoQuarterState(this)), m_sold_out_state(new SoldOutState(this)), m_sold_state(new SoldState(this)), m_count(n_gumballs) { //delete m_state; //Should not be possible if (m_count) { SetState(GetNoQuarterState()); } else { SetState(GetSoldOutState()); } } //--------------------------------------------------------------------------- void GumballMachine::EjectQuarter() { m_state->EjectQuarter(); } //--------------------------------------------------------------------------- int GumballMachine::GetCount() const { assert(m_count >= 0); return m_count; } //--------------------------------------------------------------------------- State * GumballMachine::GetHasQuarterState() { return m_has_quarter_state.get(); } //--------------------------------------------------------------------------- State * GumballMachine::GetNoQuarterState() { return m_no_quarter_state.get(); } //--------------------------------------------------------------------------- State * GumballMachine::GetSoldOutState() { return m_sold_out_state.get(); } //--------------------------------------------------------------------------- State * GumballMachine::GetSoldState() { return m_sold_state.get(); } //--------------------------------------------------------------------------- const State * GumballMachine::GetState() const { return m_state; } //--------------------------------------------------------------------------- void GumballMachine::InsertQuarter() { m_state->InsertQuarter(); } //--------------------------------------------------------------------------- void GumballMachine::ReleaseBall() { std::cout << "A gumball comes rolling out of the solt...\n"; --m_count; assert(m_count >= 0); } //--------------------------------------------------------------------------- void GumballMachine::SetState(State * const state) { assert(state); //No need to delete the old m_state, this is done //by the boost::scoped_ptr's m_state = state; } //--------------------------------------------------------------------------- void GumballMachine::TurnCrank() { m_state->TurnCrank(); } //--------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& os, const GumballMachine& gumballMachine) { os << "Mighty Gumball, Inc.\n" << "C++-enabled Standing Gumball Model #2004\n" << "Inventory: " << gumballMachine.GetCount() << " gumballs\n" << gumballMachine.GetState()->GetDescription() << '\n'; return os; } //--------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& os, const GumballMachine * const gumballMachine) { assert(gumballMachine); return operator<<(os,*gumballMachine); } //--------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& os, const boost::scoped_ptr<GumballMachine>& gumballMachine) { assert(gumballMachine); return operator<<(os,gumballMachine.get()); } //---------------------------------------------------------------------------
gumballmachine.h
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #ifndef GUMBALLMACHINE_H #define GUMBALLMACHINE_H //--------------------------------------------------------------------------- #include <iosfwd> //--------------------------------------------------------------------------- #include <boost/checked_delete.hpp> #include <boost/scoped_ptr.hpp> //--------------------------------------------------------------------------- struct State; //--------------------------------------------------------------------------- struct GumballMachine { GumballMachine(const int n_gumballs = 0); void EjectQuarter(); void InsertQuarter(); void TurnCrank(); void ReleaseBall(); int GetCount() const; //State machinery State * GetNoQuarterState(); State * GetHasQuarterState(); State * GetSoldOutState(); State * GetSoldState(); const State * GetState() const; void SetState(State * const state); private: virtual ~GumballMachine() {} //Do not forget the template brackets, as stated in //Herb Sutter. Exceptional C++ style. 2005. ISBN: 0-201-76042-8. Item 8: 'Befriending templates'. friend void boost::checked_delete<>(GumballMachine* x); boost::scoped_ptr<State> m_has_quarter_state; boost::scoped_ptr<State> m_no_quarter_state; boost::scoped_ptr<State> m_sold_out_state; boost::scoped_ptr<State> m_sold_state; State * m_state; int m_count; }; //--------------------------------------------------------------------------- std::ostream& operator<<(std::ostream& os, const GumballMachine& gumballMachine); std::ostream& operator<<(std::ostream& os, const GumballMachine * const gumballMachine); std::ostream& operator<<(std::ostream& os, const boost::scoped_ptr<GumballMachine>& gumballMachine); //--------------------------------------------------------------------------- #endif // GUMBALLMACHINE_H
hasquarterstate.cpp
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #include <cassert> #include <iostream> //--------------------------------------------------------------------------- #include "gumballmachine.h" #include "hasquarterstate.h" //--------------------------------------------------------------------------- HasQuarterState::HasQuarterState(GumballMachine * gummballMachine) : m_gumballMachine(gummballMachine) { assert(m_gumballMachine); //delete m_gumballMachine; //Should not be possible } //--------------------------------------------------------------------------- void HasQuarterState::Dispense() { std::cout << "No gummball dispensed\n"; } //--------------------------------------------------------------------------- void HasQuarterState::EjectQuarter() { std::cout << "Quarter returned\n"; //Change the state m_gumballMachine->SetState( m_gumballMachine->GetNoQuarterState()); } //--------------------------------------------------------------------------- const std::string HasQuarterState::GetDescription() const { return "The machine has had a quarter inserted"; } //--------------------------------------------------------------------------- void HasQuarterState::InsertQuarter() { std::cout << "You can insert another quarter\n"; } //--------------------------------------------------------------------------- void HasQuarterState::TurnCrank() { std::cout << "You turned...\n"; //Change the state m_gumballMachine->SetState( m_gumballMachine->GetSoldState()); } //---------------------------------------------------------------------------
hasquarterstate.h
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #ifndef HASQUARTERSTATE_H #define HASQUARTERSTATE_H //--------------------------------------------------------------------------- #include "state.h" //--------------------------------------------------------------------------- struct GumballMachine; //--------------------------------------------------------------------------- struct HasQuarterState : public State { HasQuarterState(GumballMachine * gummballMachine); void Dispense(); void EjectQuarter(); const std::string GetDescription() const; void InsertQuarter(); void TurnCrank(); GumballMachine * const m_gumballMachine; }; //--------------------------------------------------------------------------- #endif // HASQUARTERSTATE_H
main.cpp
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #include <cassert> #include <iostream> //--------------------------------------------------------------------------- #include <boost/scoped_ptr.hpp> //--------------------------------------------------------------------------- #include "state.h" #include "gumballmachine.h" //--------------------------------------------------------------------------- int main() { boost::scoped_ptr<GumballMachine> gumballMachine( new GumballMachine(5)); //delete gumballMachine.get(); //Should not be possible assert(gumballMachine); std::cout << '\n' << gumballMachine << '\n'; gumballMachine->InsertQuarter(); gumballMachine->TurnCrank(); std::cout << '\n' << gumballMachine << '\n'; gumballMachine->InsertQuarter(); gumballMachine->TurnCrank(); gumballMachine->InsertQuarter(); gumballMachine->TurnCrank(); std::cout << '\n' << gumballMachine << '\n'; } //---------------------------------------------------------------------------
noquarterstate.cpp
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #include <cassert> #include <iostream> //--------------------------------------------------------------------------- #include "gumballmachine.h" #include "noquarterstate.h" //--------------------------------------------------------------------------- NoQuarterState::NoQuarterState(GumballMachine * gummballMachine) : m_gumballMachine(gummballMachine) { assert(m_gumballMachine); //delete m_gumballMachine; //Should not be possible } //--------------------------------------------------------------------------- void NoQuarterState::Dispense() { std::cout << "You need to pay first\n"; } //--------------------------------------------------------------------------- void NoQuarterState::EjectQuarter() { std::cout << "You haven\'t inserted a quarter\n"; } //--------------------------------------------------------------------------- const std::string NoQuarterState::GetDescription() const { return "The gumballmachine has gumballs in it, but no quarter inserted"; } //--------------------------------------------------------------------------- void NoQuarterState::InsertQuarter() { std::cout << "You inserted a quarter\n"; //Change the state m_gumballMachine->SetState( m_gumballMachine->GetHasQuarterState()); } //--------------------------------------------------------------------------- void NoQuarterState::TurnCrank() { std::cout << "You turned, but there\'s no quarter\n"; } //---------------------------------------------------------------------------
noquarterstate.h
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #ifndef NOQUARTERSTATE_H #define NOQUARTERSTATE_H //--------------------------------------------------------------------------- #include "state.h" //--------------------------------------------------------------------------- struct GumballMachine; //--------------------------------------------------------------------------- struct NoQuarterState : public State { NoQuarterState(GumballMachine * gummballMachine); void Dispense(); void EjectQuarter(); const std::string GetDescription() const; void InsertQuarter(); void TurnCrank(); GumballMachine * const m_gumballMachine; }; //--------------------------------------------------------------------------- #endif // NOQUARTERSTATE_H
soldoutstate.cpp
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #include <cassert> #include <iostream> //--------------------------------------------------------------------------- #include "gumballmachine.h" #include "soldoutstate.h" //--------------------------------------------------------------------------- SoldOutState::SoldOutState(GumballMachine * gummballMachine) : m_gumballMachine(gummballMachine) { assert(m_gumballMachine); //delete m_gumballMachine; //Should not be possible } //--------------------------------------------------------------------------- void SoldOutState::Dispense() { std::cout << "You need to pay first\n"; } //--------------------------------------------------------------------------- void SoldOutState::EjectQuarter() { std::cout << "You haven\'t inserted a quarter\n"; } //--------------------------------------------------------------------------- const std::string SoldOutState::GetDescription() const { return "The gumballmachine is empty and has no quarter inserted"; } //--------------------------------------------------------------------------- void SoldOutState::InsertQuarter() { std::cout << "You inserted a quarter\n"; //Change the state m_gumballMachine->SetState( m_gumballMachine->GetHasQuarterState()); } //--------------------------------------------------------------------------- void SoldOutState::TurnCrank() { std::cout << "You turned, but there\'s no quarter\n"; } //---------------------------------------------------------------------------
soldoutstate.h
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #ifndef SOLDOUTSTATE_H #define SOLDOUTSTATE_H //--------------------------------------------------------------------------- #include "state.h" //--------------------------------------------------------------------------- struct GumballMachine; //--------------------------------------------------------------------------- struct SoldOutState : public State { SoldOutState(GumballMachine * gummballMachine); void Dispense(); void EjectQuarter(); const std::string GetDescription() const; void InsertQuarter(); void TurnCrank(); GumballMachine * const m_gumballMachine; }; //--------------------------------------------------------------------------- #endif // SOLDOUTSTATE_H
soldstate.cpp
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #include <cassert> #include <iostream> //--------------------------------------------------------------------------- #include "gumballmachine.h" #include "soldstate.h" //--------------------------------------------------------------------------- SoldState::SoldState(GumballMachine * gummballMachine) : m_gumballMachine(gummballMachine) { assert(m_gumballMachine); //delete m_gumballMachine; //Should not be possible } //--------------------------------------------------------------------------- void SoldState::Dispense() { m_gumballMachine->ReleaseBall(); if (m_gumballMachine->GetCount() > 0) { //Change the state m_gumballMachine->SetState( m_gumballMachine->GetNoQuarterState()); } else { std::cout << "Oops, out of gumballs\n"; //Change the state m_gumballMachine->SetState( m_gumballMachine->GetSoldOutState()); } } //--------------------------------------------------------------------------- void SoldState::EjectQuarter() { std::cout << "Sorry, you already turned the crank\n"; } //--------------------------------------------------------------------------- const std::string SoldState::GetDescription() const { return "The gumballmachine has a gumball lying in its slot"; } //--------------------------------------------------------------------------- void SoldState::InsertQuarter() { std::cout << "Please wait, we\'re already giving you a gumball\n"; } //--------------------------------------------------------------------------- void SoldState::TurnCrank() { std::cout << "Turning twice doesn\'t get you another gumball\n"; } //---------------------------------------------------------------------------
soldstate.h
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #ifndef SOLDSTATE_H #define SOLDSTATE_H //--------------------------------------------------------------------------- #include "state.h" //--------------------------------------------------------------------------- struct GumballMachine; //--------------------------------------------------------------------------- struct SoldState : public State { SoldState(GumballMachine * gummballMachine); void Dispense(); void EjectQuarter(); const std::string GetDescription() const; void InsertQuarter(); void TurnCrank(); GumballMachine * const m_gumballMachine; }; //--------------------------------------------------------------------------- #endif // SOLDSTATE_H
state.h
//--------------------------------------------------------------------------- /* CppDesignPatternState, demonstrates the State design pattern Copyright 2011 Richel Bilderbeek This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ //--------------------------------------------------------------------------- //From http://www.richelbilderbeek.nl/CppDesignPatternState.htm //--------------------------------------------------------------------------- #ifndef STATE_H #define STATE_H //--------------------------------------------------------------------------- #include <string> //--------------------------------------------------------------------------- #include <boost/checked_delete.hpp> //--------------------------------------------------------------------------- struct State { //All state transitions are abstract methods virtual void Dispense() = 0; virtual void EjectQuarter() = 0; virtual void InsertQuarter() = 0; virtual void TurnCrank() = 0; virtual const std::string GetDescription() const = 0; protected: virtual ~State() {} //Do not forget the template brackets, as stated in //Herb Sutter. Exceptional C++ style. 2005. ISBN: 0-201-76042-8. Item 8: 'Befriending templates'. friend void boost::checked_delete<>(State* x); }; //--------------------------------------------------------------------------- #endif // STATE_H
References
- Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Design Patterns. 1995. ISBN: 0201633612.
- Eric Freeman, Elisabeth Freeman. Head First Design Patterns. 2004. ISBN: 978-0-596-00712-6.