TSE3 Commands
The TSE3::Cmd
namespace contains classes that implement a
GoF Command pattern. You can use this in applications that use the
TSE3 library to provide a command history with undo/redo facilities.
However, in order to use these classes there are a number of provisos
that you must take care to note:
- The commands
There is a TSE3::Cmd
class for every useful operation
on the Song
data structure and it's subcomponents. There
are not commands for alterations to the state of objects like
Transport
and Metronome
since they are
system wide settings, not Song
alterations.
- The
CommandHistory
class
The CommandHistory
class holds the list of commands.
For any operation, you create a Command
object for it
(with new
), call execute()
on the command,
and then add
it to the CommandHistory
class.
For now on you can call undo
and redo
on the
CommandHistory
to undo/redo the history of operations.
Remember that your application will be kept up to date with the
resulting changes to the Song
through the
Notifier
interface mechanism.
- Multiple
Song
s
If you support multiple Song
objects in your application
you can either use one CommandHistory
class for all
operations, or create a separate CommandHistory
for
each Song
. It is this latter operation that is the most
logical, and the TSE3_Application::Application
class
contains support for it.
- If you use commands, don't directly use the TSE3 API
If you are using TSE3 Commands then any change to a Song
or it's subcomponents must be done through commands. Otherwise,
if the state of the Song
changes between a command
being execute
d and undo
ne unpredicatable
results may occur.
- Writing your own commands
If you implement your own commands that are creational or destrutional
(if that is a word ;-) you must take care. If you, for example, create
a new Part
in execute
you should not
delete it in undo
and then create a different
Part
in a subsequent call to execute
. Why?
If any subsequent commands act on that Part
and take a
Part*
parameter to identify it, by deleting the
Part
and creating a new different one on a 'redo' you
will cause the later command to be invalid.
Creational patterns should create objects in the constructors,
put them into the Song
in undo, and delete the object
in the destructor only if the object is deleted after having
been undone.
Destructional commands should merely remove the object in
execute
and put the same object back in in
undo
. The object may only be deleted in the destructor
if the command has not been undone.
However, despite these provisos and the extra care that you must take when
using the command pattern in your application, the benefits are great:
the undo/redo facility is a really user-friendly useful facility that sets
a good application appart from a great one.