// Purpose. Memento design pattern // 1. Assign the roles of "caretaker" and "originator" // 2. Create a "memento" class and declare the originator a friend // 3. Caretaker knows when to "check point" the originator // 4. Originator creates a memento and copies its state to the memento // 5. Caretaker holds on to (but cannot peek in to) the memento // 6. Caretaker knows when to "roll back" the originator // 7. Originator reinstates itself using the saved state in the memento #include #include using namespace std; class Memento { // 2. Create a "memento" class and friend class Stack; // declare the originator a friend int *items, num; Memento( int* arr, int n ) { items = new int[num = n]; for (int i=0; i < num; i++) items[i] = arr[i]; } public: ~Memento() { delete items; } }; class Stack { // 1. Stack is the "originator" int items[10], sp; public: Stack() { sp = -1; } void push( int in ) { items[++sp] = in; } int pop() { return items[sp--]; } bool isEmpty() { return sp == -1; } // 4. Originator creates a memento and copies its state to the memento Memento* checkPoint() { return new Memento( items, sp+1 ); } // 7. Originator reinstates itself using the saved state in the memento void rollBack( Memento* m ) { sp = m->num-1; for (int i=0; i < m->num; i++) items[i] = m->items[i]; } friend ostream& operator<< ( ostream& os, const Stack& s ) { string buf( "[ " ); for (int i=0; i < s.sp+1; i++) { buf += s.items[i]+48; buf += ' '; } buf += ']'; return os << buf; // stack is [ 0 1 2 3 4 ] } }; // stack is [ 0 1 2 3 4 5 6 7 8 9 ] // popping stack: 9 8 7 6 5 4 3 2 1 0 // 1. main() is the "caretaker" // stack is [ ] void main( void ) { // second is [ 0 1 2 3 4 5 6 7 8 9 ] Stack s; // first is [ 0 1 2 3 4 ] for (int i=0; i < 5; i++) s.push( i ); // popping stack: 4 3 2 1 0 cout << "stack is " << s << endl; Memento* first = s.checkPoint(); // 3. Caretaker knows when to save for (i=5; i < 10; i++) s.push( i ); // 5. Caretaker holds on to memento cout << "stack is " << s << endl; Memento* second = s.checkPoint(); // 3. Caretaker knows when to save cout << "popping stack: "; // 5. Caretaker holds on to memento while ( ! s.isEmpty()) cout << s.pop() << ' '; cout << endl; cout << "stack is " << s << endl; s.rollBack( second ); // 6. Caretaker knows when to undo cout << "second is " << s << endl; s.rollBack( first ); // 6. Caretaker knows when to undo cout << "first is " << s << endl; cout << "popping stack: "; while ( ! s.isEmpty()) cout << s.pop() << ' '; cout << endl; delete first; delete second; } // Purpose. Memento design pattern // // Discussion. A memento is an object that stores a snapshot of the // internal state of another object. It can be leveraged to support // multi-level undo of the Command pattern. In this example, before a // command is run against the Number object, Number's current state is // saved in Command's static memento history list, and the command itself // is saved in the static command history list. Undo() simply "pops" the // memento history list and reinstates Number's state from the memento. // Redo() "pops" the command history list. Note that Number's encapsula- // tion is preserved, and Memento is wide open to Number. #include class Number; class Memento { public: Memento( int val ) { _state = val; } private: friend class Number; // not essential, but p287 suggests this int _state; }; class Number { public: Number( int value ) { _value = value; } void dubble() { _value = 2 * _value; } void half() { _value = _value / 2; } int getValue() { return _value; } Memento* createMemento() { return new Memento( _value ); } void reinstateMemento( Memento* mem ) { _value = mem->_state ; } private: int _value; }; class Command { public: typedef void (Number::* Action)(); Command( Number* receiver, Action action ) { _receiver = receiver; _action = action; } virtual void execute() { _mementoList[_numCommands] = _receiver->createMemento(); _commandList[_numCommands] = this; if (_numCommands > _highWater) _highWater = _numCommands; _numCommands++; (_receiver->*_action)(); } static void undo() { if (_numCommands == 0) { cout << "*** Attempt to run off the end!! ***" << endl; return; } _commandList[_numCommands-1]->_receiver-> reinstateMemento( _mementoList[_numCommands-1] ); _numCommands--; } void static redo() { if (_numCommands > _highWater) { cout << "*** Attempt to run off the end!! ***" << endl; return; } (_commandList[_numCommands]->_receiver-> *(_commandList[_numCommands]->_action))(); _numCommands++; } protected: Number* _receiver; Action _action; static Command* _commandList[20]; static Memento* _mementoList[20]; static int _numCommands; static int _highWater; }; Command* Command::_commandList[]; Memento* Command::_mementoList[]; int Command::_numCommands = 0; int Command::_highWater = 0; void main() { int i; cout << "Integer: "; cin >> i; Number* object = new Number(i); Command* commands[3]; commands[1] = new Command( object, &Number::dubble ); commands[2] = new Command( object, &Number::half ); cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: "; cin >> i; while (i) { if (i == 3) Command::undo(); else if (i == 4) Command::redo(); else commands[i]->execute(); cout << " " << object->getValue() << endl; cout << "Exit[0], Double[1], Half[2], Undo[3], Redo[4]: "; cin >> i; } } // Integer: 11 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2 // 5 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 1 // 10 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 2 // 5 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3 // 10 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3 // 5 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3 // 11 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 3 // *** Attempt to run off the end!! *** // 11 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4 // 5 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4 // 10 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4 // 5 // Exit[0], Double[1], Half[2], Undo[3], Redo[4]: 4 // *** Attempt to run off the end!! *** // 5