Think about the implementation of macros in a Microsoft Office application for example that is a sequence
of commands that gets recorded one after another and you can sort of you can play back all the commands
one after another and you can also undo them all in reverse order with a single invocation.
So we're going to do the same thing here by basically turning a vector of commands into a separate object
which also has methods called call an undo which operate on a chunk of different commands at the same
time.
This is something that's called the composite design pattern by the way so here we're going to merge
the composite design pattern with the command design pattern.
So how do we do this.
Well first of all let's try to do a very naive implementation of the composite command.
Right.
So I'm going to have a structure called composite bank account commander.
Now what I'm going to do is I'm going to inherit from a vector of bank account command.
Now inheriting from vector could be tricky because it doesn't have a virtual destructor but it's not
a problem in our case.
And we have to implement the command interface as well.
There we go.
OK.
So the idea is as follows you initialize the composite bank account command with a set of commands that
you want to invoke and then you can call them in a single function call and you can undo them in a single
function call.
So let's generate the constructor.
Let's actually see what Sea-Lion offers us because I want to constructor which has an initializer list
but doesn't have any additional arguments so I'll generate one of these and I'll get rid of the second
argument.
I don't really care about that too much.
Let's get rid of it like this.
Now in terms of initialization what I'm going to do is I'm going to just initialize the vector with
an I-List.
I don't really like this name to be honest.
Let's just let's just rename it two items for example that's a lot more friendly I think.
OK so this is a constructor that we've generated.
And now what we can do is we can implement the command interface.
So implement functions and that's implemented both goal and undo.
Now the operations here are going to be identical to the operations that we did here and here.
Actually we can copy this code.
I think we can just copy this.
And obviously we're iterating ourselves so that's star this we're iterating the classwork currently.
And so for auto ACMD in this for the call we just call each of the commands inside it and the same goes
for this particular thing.
So let's face it correctly.
So instead of commands here we just remove the commands basically because we have a member begin.
So like so and get rid of commands here as well no go.
OK so this is our implementation of Colan undo for a composite bank account command.
And you could be forgiven for thinking that.
Now we can use this to model let's say a bank transfer.
So what is a money transfer money transfer is two commands.
In one you take out the money from one account you put it into another account so you might think hey
let's let's just do this let's do a money transfer command which is going to be a composite bank account
command.
OK so let's initialize it in the constructor actually.
So I'm going to have a constructor.
Well let's just keep it.
Oh wait.
Hold on.
It's passing in the whole initializer list not the kind of constructor that I want to be honest that's
not the kind of constructor I'm interested in.
Let's have a similar one.
So you have a money transfer command and the kind of things that we want we want to know which bank
account we operate on.
So bank accounts from which bank account are we taking the money from the bank accounts we're depositing
the money too.
And obviously the amount.
So these are the right arguments.
Now what we're going to be doing is we're going to be calling the base class constructor obviously because
we have to basically.
So we're going to be calling the composit bank account command and we're going to be passing it a vector
of the commands to initialize with.
So that's going to be a vector.
Actually I think we can use uniform initialization here just curly braces so we're going to have a bank
account command which takes the money from this account by simulating a withdrawal so that's going to
be bank accounts come and withdraw a certain amount and then the second of these commands is going to
be similar but we're going to be putting money into the target accounts.
So who goes into the two accounts.
The operation is a deposit.
And we put in a certain amount.
So this is actually legitimate code this is OK to begin with.
And so if we want to do a transfer Let's actually simulate a transfer I'm going to get rid of all of
this.
So all have bank account be a and b a two and now.
Well first of all we have to put some money into the bank account to be able to transfer it so let's
put let's do the deposit 100 and then we'll try to even out the accounts by making a deposit from one
to another over exactly 50.
So what I'll do is I'll make a money transfer command CMD.
And that's going to take the arguments from which accounts to transfer to which account I want the money
to go and let's put 50 here.
So after we perform this command by doing CME the call we can then print out the diagnostics on the
first and second bank accounts so see outby and line 2 and line and then we can try undoing the whole
thing and we can try on doing the whole thing.
So once again I'll say Siham the UNDO here and we're going to see what happens when we undo this composite
command.
All right.
So lots of stuff happening here.
We deposit some money we withdraw some money blah blah blah and then the interesting part for us is
figuring out the final balances of the NBA to after each operation.
So at the moment after we perform both of them both of the parts of the transfer we have balances of
50 50 which is correct.
And towards the end we reverted back to balances of 100 and 0 which is once again correct.
Now unfortunately this implementation is going to fail if I decide that I want to transfer a huge amount
of money.
Let's just suppose I want to transfer five thousand.
Now this is way over the overdraft limit of the first bank account so the transfer should fail completely.
We shouldn't make any changes at all.
But unfortunately we will make changes because neither of the bank account commands knows about the
fact that the other command has failed.
So as you can see somewhat unpleasant things are happening so now we have a balance of 100 on the first
one because obviously we didn't withdraw any money we couldn't.
But on the second one the balance is now thousand which shouldn't happen at all.
And so what do we want to do with this.
Well we want to somehow make sure that the commands are all tied to one another so that if one of them
fails then the other fails as well.
So let's see how we can do this.
We're going to make a new implementation of a composite bank account command and this one is going to
be called a dependent composite command so structure dependent composite command.
And it's going to be actually inheriting from the composite bank accounts command.
So it's going to be a refinement on something that we've done already.
Now here once again I have to have the constructor unfortunately.
Let's see we can generate the constructor that we go.
I think I can just go in here and create the constructor which takes the initialiser list whatever.
So after this what I want to do is I want to override the call function.
So I'm going to do an override for the call.
And what I'm going to do here is I'm basically going to change the semantics now.
Let me just check what's going on here.
Base class composite bank account command does not have the full control.
Well actually I'm not calling the default constructor I wonder what the issue is here.
OK so we want to override the implementation of code and here what we want to do is we want to check
that they all succeed basically And if the previous command failed then the subsequent command doesn't
even get cold.
So here I'll have a flag OK with a default value of true.
I'm going to go through all the commands were going to be checking this flag.
If it's not OK we just don't continue anymore.
So for each of the commands in the current object if the flag is OK then we can actually call the command
so we can say C.M. did call but we said the OK flag to the result of that call so we say OK equals CMD
you don't succeed it and subsequently otherwise if OK is false that means we cannot even call the command
and we just say that the command invocation failed so we say ACMD the Succeed that equals false and
we don't even try to call it.
So now what we can do is we can use this base class so I can take this base concept and I can use it
instead of the ordinary composite bank account come out as the base class of money transfer command.
Now should actually work just fine.
I don't know where the highlighting comes from and Sea-Lion it sometimes panics and things that you
know things aren't going the way that they're supposed to be going but everything is correct here.
So what we can do is we can try running this again and see what we get.
This time round and hooray the operations are now consistent.
So we start with a balance of one hundred and 0 and the whole thing fails so we don't get any output
between this and the final check of the balances.
So this is just a small illustration of the kind of problems that you can encounter as you have commands
depending on other command.
So it's very easy to make a vector of them but it's a little harder to actually make sure that you get
some eventual consistency.
And let me give you another example of how it can fail.
Let's suppose that the first command succeeds but the second command fails so let's suppose that the
transfer the withdrawal actually succeeds.
But you cannot deposit because the count has been blocked so you want to roll back the whole thing.
And then of course you have to make sure that eventually you undo the withdrawal correctly and maybe
you undo it immediately because it makes no sense to perform the entire command.
If the second operation cannot succeed.
So these kinds of mechanics they get added and that's why you get this composite command as an extension
of the ordinary command design pattern because you want additional logic you want commands depending
on other commands and into playing with other commands and the complexity of this is really up to you.