Hi Andreas, An undo library seems to be on a boundary between patterns and library functions, so im interested in seeing how something like an undo library plays out.
Some things ive come across include: - The need to keep objects utilized in doIt() alive until they leave the undo list (this sometimes is even beyond serialization). Implementers of command objects frequently use some type of shared_ptr to keep things alive after use (until they fall off the undo queue). - The need to keep things simple, as Steven Kirk noted. This competes with the need to employ a more complex (as applications grow) command / command-manager interface. Providing a command-base-imp might be a way to satisfy both users. - The ability for commands that can not support undo to inform the manager (sending an email, committing transactions, or a developer testing new objects are examples of commands that do not support undo). When these commands are executed, they clear the undo-stack (this can be augmented in a UI app with a message informing the user they are about to execute an undoable command). - The need to support various command managers. People may want to extend the behavior of the undo-manager, but often start out with a default manager (templatizing the manager's container might also be an option). The code below might help illustrate the suggestions mentioned above (and by S.Kirk in the previous email) for the command class (The manager interface is a separate discussion probably :-). - Steve struct command { virtual void doIt() = 0; // Called first time virtual void undoIt() = 0; // Called to undo virtual void redoIt() = 0; // Called after first time virtual bool supportsUndo() = 0; virtual bool supportsRedo() = 0; virtual ~command() {} }; struct commandBinder : public command { commandBinder( const boost::function<void> &doItFn, const boost::function<void> &redoItFn = &commandBinder::redoUnsupported, const boost::function<void> &undoItFn = &commandBinder::undoUnsupported ) : m_doItFunction( doItFn ), m_undoItFunction( undoItFn ), m_redoItFunction( redoItFn ) {} virtual void invokeCommand( const boost::function<void> &fn, const std::string &msg ) { if ( fn.empty() ) throw undo_exception( msg.c_str() ); else fn(); } virtual void doIt() { invokeCommand( m_doItFunction, "" ); } virtual void redoIt() { invokeCommand( m_redoItFunction, "redoIt unsupported" ); } virtual void undoIt() { invokeCommand( m_undoItFunction, "undoIt unsupported" ); } virtual bool supportsUndo() { return !m_undoItFunction.empty(); } virtual bool supportsRedo() { return !m_redoItFunction.empty(); } boost::function<void> m_doItFunction; boost::function<void> m_redoItFunction; boost::function<void> m_undoItFunction; static void undoUnsupported() {} static void redoUnsupported() {} virtual ~commandBinder() {} }; _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost