// Purpose. State design pattern lab // // Problem. A large monolithic case drives the application. As // the program evolves, this case statemen may have to be duplicated in // multiple places. We want to migrate to an OO design, but we need to be // careful not to encapsulate multiple distinct "behaviors" in a single // object. // // FSM: Message ==> on off ack // State A A B C // State B A C // State C B // // Assignment. // o Define an FSM context (wrapper, handle, interface) class // o FSM declares a private data member of type FSMstate* to remember its // "current state" // o FSM defines the member functions on(), off(), and ack(). Each of these // functions delegates to the contained object by calling its member func- // tion of the same name, and passing the FSM's "this" pointer. [GOF, p310, // bottom] // o FSM declares class FSMstate as friend (because FSMstate will be setting // the "current state" member) // o Define an FSMstate base class // o FSMstate defines a default implementation for all FSM messages (on, off, // ask). The implementation of each will look like - // virtual void on( FSM* ) { cout << "undefined combo" << endl; } // o FSMstate defines a protected member function - // void changeState( FSM*, FSMstate* ) // This is used by the derived state classes to set the "current state" // member of the FSM. This "indirection" is necessary because "friendship" // is not inherited by derived classes. [GOF, p311] // o Declare states A, B, and C as derived classes of FSMstate // o Design states A, B, and C as Singletons // o Each of these classes override only those messages that they respond to // o The bodies of the on(), off(), and ack() methods are simply the bodies // of the "case" clauses below, except that the state machine's state is // changed by calling the base class's changeState() method and passing the // "instance" of the desired FSMstate derived class. [Note: state // transitions are defined in each individual state object. This results // in coupling between the derived classes, but it also provides for // decentralization of intelligence or control.] // o FSM's constructor initializes its "current state" member to state "B" // o The body of main() reduces to "FSM fsm;" plus a minimal driver loop #include enum State { A, B, C }; enum Message { on, off, ack }; State currentState; Message messageArray[10] = { on,off,off,ack,ack,ack,ack,on,off,off }; void main( void ) { currentState = B; for (int index=0; index < 10; index++) { if (currentState == A) { if (messageArray[index] == on) { cout << "A, on ==> A" << endl; currentState = A; } else if (messageArray[index] == off) { cout << "A, off ==> B" << endl; currentState = B; } else if (messageArray[index] == ack) { cout << "A, ack ==> C" << endl; currentState = C; } } else if (currentState == B) { if (messageArray[index] == on) { cout << "undefined combo" << endl; } else if (messageArray[index] == off) { cout << "B, off ==> A" << endl; currentState = A; } else if (messageArray[index] == ack) { cout << "B, ack ==> C" << endl; currentState = C; } } else if (currentState == C) { if (messageArray[index] == on) { cout << "undefined combo" << endl; } else if (messageArray[index] == off) { cout << "undefined combo" << endl; } else if (messageArray[index] == ack) { cout << "C, ack ==> B" << endl; currentState = B; } } } } // undefined combo // B, off ==> A // A, off ==> B // B, ack ==> C // C, ack ==> B // B, ack ==> C // C, ack ==> B // undefined combo // B, off ==> A // A, off ==> B