When you cancel 2 things, you take a completely new action, you need to โforgetโ the history of the replay and replace it with a new command, right?
For instance...
- Add as friend Jim
- Add Friend Bill
- Add Friend Jill
- Remove Jim
- Cancel
- Cancel
The state should be "Jim" and "Bill."
So, you really need only one list and a pointer to the current "command", for example ...
// Note: NOT thread safe! public class CommandStack { private List<Command> commands = Collections.emptyList(); private int nextPointer = 0; public void doCommand(Command command) { List<Command> newList = new ArrayList<>(nextPointer + 1) for(int k = 0; k < nextPointer; k++) { newList.add(commands.get(k)); } newList.add(command); commands = newList; nextPointer++; // Do the command here, or return it to whatever called this to be done, or maybe it has already been done by now or something // (I can only guess on what your code currently looks like...) command.execute(); } public boolean canUndo() { return nextPointer > 0; } public void undo() { if(canUndo()) { nextPointer--; Command commandToUndo = commands.get(nextPointer); // Undo the command, or return it to whatever called this to be undone, or something command.undo(); } else { throw new IllegalStateExcpetion("Cannot undo"); } } public boolean canRedo() { return nextPointer < commands.size(); } public void redo() { if(canRedo()) { commandToDo = commands.get(nextPointer); nextPointer++; // Do the command, or return it to whatever called this to be re-done, or something commandToDo.execute(); } else { throw new IllegalStateException("Cannot redo"); } } }
If I...
interface Command { /* execute / undo etc */ } public class AddFriendCommand implements Command { private String friendName; // ... other fields, constructor / getters etc ... public void execute() { // Actually do it... System.out.println("Added friend " + name); } public void undo() { // Undo it... System.out.println("Removed friend " + name); } } public class RemoveFriendCommand implements Command { private String friendName; // ... other fields, constructor / getters etc ... public void execute() { // Actually do it, maybe throw exception if friend does not exist? // (that would have to be a runtime exception unless you want the interface method to throw stuff); System.out.println("Removed friend " + name); } public void undo() { // Undo it... System.out.println("Added friend " + name); } }
You can repeat the above sequence using ...
CommandStack stack = new CommandStack(); stack.doCommand(new AddFriendCommand("Jim")); stack.doCommand(new AddFriendCommand("Bill")); stack.doCommand(new AddFriendCommand("Jill")); stack.doCommand(new RemoveFreindCommand("Jim")); stack.undo(); stack.undo();
If you have now made a new command (via doCommand), it will forget that you have ever added โJillโ or deleted โJimโ, but instead will now remember the new command and the rest of the command history, which has not been canceled.
Hope this helps.
Bretc source share