Understanding the Problem
Ordinary code statements are perishable, for example
you cannot undo a field/property assignment
you cannot directly take a sequence of actions that you just made and you cannot serialise them (to a db for example)
there is no "record" for this series of operations
The command object enables us to create an object that represents an operation
This pattern has use cases in GUI commands, multi-level undo/redo, macro recording and more for example in Excel a MACRO is a sequence of commands that gets recorded one after another and they can be played back again and again and we can also undo them one by one or all at once ,this is also a representation of command design pattern
The command design pattern is an object which represents an instruction to perform a particular action. It contains all the info necessary for the action to be taken
-
Suppose we want to manipulate the above bank account such that we have a proper record that the bank account was manipulated
We can directly call the
deposit
andwithdraw
functions from the above class instance but they would be perishable and we would not be able to maintain a log for themSo we are going to create an extra object -Command- for performing all operations
-
Above we have a list of commands - a record of our operations, we have our audit log now on how the account was manipulated, we can even add functionality for rollback now (undo our commands now)
-
but undo functionality must be implemented carefully, if somebody wants to withdraw the money and the operation fails, undoing such an operation should also do nothing
If we assume that the undo and redo operations are symmetric - which they are not ,undo operations of the command can be implemented like :
-
so currently in the above code, if somebody who doesn't have a million withdraws a million, the operation will fail but if we undo that operation - a million dollars would be deposited - this is because undo and redo in this case are not symmetric- this can be solved by simply maintaining a success flag with every command
So the command abstraction will now look like
So there we have it we have done undo/redo operations and also maintained a log of all the bank account modifications we do using the command design pattern
NOTE
- Command Query Separation(CQS): Command causes mutation whereas a query does not cause mutation but returns a value