/////////////////////////////////////////////////////////////// // state.cpp - defines states in terms of the events // // that trigger transitions to another state // // // // ver 1.1 Adds hooks for new state // // Language: Visual C++, ver 5.0 // // Platform: Micron Dual Pentium 200, NT 4.0 // // Application: Design Patterns - property pattern, Su98 // // Author: Jim Fawcett, CST 2-187, (314) 443-3948 // // fawcett@neptune.syr.edu // /////////////////////////////////////////////////////////////// #include #include #include "state.h" /////////////////////////////////////////////////////////////// // Context struct // - Context iss private to this file, e.g., just part of // implementation, so no loss of encapsultation. struct Context { Context() { registry.resize(numStates); } ~Context() { for (ElevBase* pState : registry) delete pState; } // an extensible enumeration of states const int numStates = 5; const int onFF = 0; const int goUp = 1; const int onSF = 2; const int goDn = 3; const int newS = 4; std::vector registry; ElevBase* pCurrState; }; Context* ElevBase::pContext_ = new Context(); // deleted in ElevBase::getEvent, case 4 //----< user interface doesn't see any public data >----------- /* * - Yes, this is a despised console menu, but hey, it's a demo! */ ElevBase* ElevBase::getEvent(ElevBase *pState) { int eventType; std::cout << "\n Enter (upButton=1, arrived=2, dnButton=3, quit = 4, Don't Select! = 5) > "; std::cin >> eventType; switch(eventType) { case 1 : return (pState->upButton()); case 2 : return (pState-> arrived()); case 3 : return (pState->dnButton()); case 4 : std::cout << "\n ending simulation\n\n"; delete pContext_; // here's were cleanup happens std::cout << "\n Press key to quit"; _getche(); return 0; //----< new event >-------------------------------------------- case 5 : pState = getRegistered(pContext_->newS); return (pState->newEvent()); //------------------------------------------------------------- default : std::cout << "\n no such state - try again"; return (getEvent(pState)); } } //----< returns a state, with bounds checking >---------------- /* * - Bounds checking needed since this function could be * used by clients. */ ElevBase* ElevBase::getRegistered(int n) { if (n < 0 || pContext_->numStates <= n) { std::cout << " unknown state\n\n"; return pContext_->registry[pContext_->onFF]; } return pContext_->registry[n]; } //----< factory function for OnFirstFloor >-------------------- ElevBase* OnFirstFloor ::makeState() { ElevBase* pElevBase = pContext_->registry[pContext_->onFF] = new OnFirstFloor (); return pElevBase; } //----< event for OnFirstFloor >-------------------------------- ElevBase* OnFirstFloor ::upButton() { pContext_->pCurrState = pContext_->registry[pContext_->goUp]; std::cout << "\n going up"; return pContext_->pCurrState; } //----< destructor used to show cleanup >---------------------- OnFirstFloor ::~OnFirstFloor () { std::cout << "\n destroying OnFirstFloor state"; } //----< factory function for GoingUp >------------------------- ElevBase* GoingUp::makeState() { ElevBase* pElevBase = pContext_->registry[pContext_->goUp] = new GoingUp(); return pElevBase; } //----< event for GoingUp >------------------------------------ ElevBase* GoingUp::arrived() { pContext_->pCurrState = pContext_->registry[pContext_->onSF]; std::cout << "\n arrived on second floor"; return pContext_->pCurrState; } //----< destructor used to show cleanup >---------------------- GoingUp::~GoingUp() { std::cout << "\n destroying GoingUp state"; } //----< factory function for OnSecondFloor >-------------------- ElevBase* OnSecondFloor::makeState() { ElevBase* pElevBase = pContext_->registry[pContext_->onSF] = new OnSecondFloor(); return pElevBase; } //----< event for OnSecondFloor>------------------------------- ElevBase* OnSecondFloor::dnButton() { pContext_->pCurrState = pContext_->registry[pContext_->goDn]; std::cout << "\n going down"; return pContext_->pCurrState; } //----< destructor used to show cleanup >---------------------- OnSecondFloor::~OnSecondFloor() { std::cout << "\n destroying OnSecondFloor state"; } //----< factory function for GoingDown >----------------------- ElevBase* GoingDown::makeState() { ElevBase* pElevBase = pContext_->registry[pContext_->goDn] = new GoingDown(); return pElevBase; } //----< event for GoingDown >---------------------------------- ElevBase* GoingDown::arrived() { pContext_->pCurrState = pContext_->registry[pContext_->onFF]; std::cout << "\n arrived on first floor"; return pContext_->pCurrState; } //----< destructor used to show cleanup >---------------------- GoingDown::~GoingDown() { std::cout << "\n destroying GoingDown state"; } //----< new state - elevator cable is breaking >--------------- class ElevCableBreaking : public ElevBase { public: //----< destructor used to show cleanup >---------------------- ~ElevCableBreaking() { std::cout << "\n destroying ElevCableBreaking state"; } //----< factory function for ElevCableBreaking >------------- static ElevBase* ElevCableBreaking::makeState() { ElevBase* pElevBase = pContext_->registry[pContext_->newS] = new ElevCableBreaking(); return pElevBase; } //----< event for ElevCableBreaking >------------------------ ElevBase* newEvent() { if (pContext_->pCurrState != pContext_->registry[pContext_->onFF]) { std::cout << "\n elevator cable breaking: help, we're falling !!!!!!\n"; std::cout << "\n arrived suddenly on first floor"; } else { std::cout << "\n elevator no longer functional, please exit elevator"; std::cout << "\n press key to try again\n "; _getch(); } pContext_->pCurrState = pContext_->registry[pContext_->onFF]; return pContext_->pCurrState; } }; //----< used for display >------------------------------------- std::string announceState(ElevBase* pBase) { return typeid(*pBase).name(); } //----< create states >---------------------------------------- ElevBase* ElevBase::makeElevStates() { ElevBase *pCurrElevState = OnFirstFloor::makeState(); std::cout << "\n created state " << announceState(pCurrElevState).c_str(); ElevBase* pState; pState = GoingUp::makeState(); std::cout << "\n created state " << announceState(pState).c_str(); pState = OnSecondFloor::makeState(); std::cout << "\n created state " << announceState(pState).c_str(); pState = GoingDown::makeState(); std::cout << "\n created state " << announceState(pState).c_str(); pState = ElevCableBreaking::makeState(); std::cout << "\n created state " << announceState(pState).c_str(); return pCurrElevState; } //----< simulation starts here >------------------------------- void main() { struct Cosmetic { ~Cosmetic() { std::cout << "\n\n"; } } cos; std::cout << "\n Two Story Elevator Simulation"; std::cout << "\n ==============================="; // anonymous scope lets us see destruction { ElevBase* pCurrElevState = ElevBase::makeElevStates(); std::cout << "\n\n current state = " << announceState(pCurrElevState).c_str(); while (pCurrElevState = pCurrElevState->getEvent(pCurrElevState)) ; } }