Instructor: Now let's come back to this problem
of having some duplicated code
and having all these extra cheques
for whether something is a payment or a refund.
We can solve this problem
by utilizing factory functions and polymorphism.
And for that of course, we need
to understand what a factory function is
and what polymorphism is.
A factory function is simply a function which is used
to produce something, for example, to produce objects
or produce maps, arrays, anything like that.
We provide a certain input,
and it then produces a certain object for us.
Polymorphism is a concept to which I will come back to
in the next course section,
which is about classes and objects.
In the end, it means that we can have an object
or a function, which we can always use in the same way,
for example, an object
on which we always can use the same method,
but what this method does in detail,
then depends on some other factors.
And we can combine this to write a factory function,
which produces different other functions or objects
with functions that we can always call in the same way,
but that then sometimes handle credit card payments,
and sometimes handle PayPal refunds for example.
And that is exactly what we're going to work on now.
We're going to write a factory function,
which creates an object,
which always will have the same structure,
but then different code
that executes under different circumstances.
Let's go up to the process transaction function again.
Here I call process by method to then trigger this function.
Now I will replace this function, so we'll add a new one,
and soon delete the old one.
And I will name this function get transaction processor.
And this function will be a factory function.
This function will return an object,
and it will actually return a polymorphic object full
of functions which always have the same name,
but will do different things.
That's the plan here.
And for that, we will utilize the fact that
in most programming languages,
you can indeed use functions like regular values.
So you can assign functions to variables to properties,
you can pass functions around.
And we're going to do that because we are going
to return an object full of functions, which already exist,
but which we won't call in here,
but which we will just swap dynamically depending
on which function we need.
But it will become clearer as we start working
on this factory function.
And for this, I want to utilize the fact that functions
in JavaScript but also
in many other programming languages are callable,
but don't have to be called.
And if you don't add the brackets after the function name,
you can use them just like any other value,
like a string, a number or an object.
So now with that, we can grab this code here,
and move that into get transaction processor,
and then add a new variable here,
in this get transaction processor function,
which in JavaScript, we do with the let keyword,
which will name processors,
because we have two possible processors
for every transaction, a payment and a refund processor.
At least after going through these cheques.
Now in here in this object, which I create like this
in JavaScript, or a map in other programming languages,
I will add q keys.
Payment with a value of null initially, so no value,
and refund with a value of null initially.
Now the idea is that we populate payment and refund
with functions as values inside of these cheques.
So here, if we use a credit card as a payment method,
I will set processors.payment,
equal to process credit card payment,
but I'm not calling this function,
I'm not adding parentheses, I'm just pointing at it.
So this process credit card function
which is defined down there, I'm pointing at it.
I'm using it as a value, I'm not executing it.
And I'm storing this pointer at this function
in this key in this object or map.
So here, I'll then do the same for refund and store process,
credit card refund in the refund field of this map.
Again just pointing at it.
And we can now do this here, in all these cases,
and just point at the different processor functions.
So here it's process PayPal payment,
at which I'm pointing here, it's process PayPal refund.
And here it's process plan payment,
and process plan refund.
So now we're populating this object,
and I am simply returning this object thereafter.
So in this get transaction processor function,
I'm creating this object,
populating the different processors depending
on the payment method, which was chosen,
and then I return this.
Now with that, we can get rid of the process
by method, function, we should keep the is payment,
and is refund helper functions,
but we can get rid of the process credit card transaction,
process PayPal transaction,
and process plan transaction functions.
So we remove a lot of code here.
In get transaction processor,
we should now accept the transaction as a parameter,
because we're using it here to derive the method.
And now we're creating this object here,
which we can now utilize
by calling get transaction processor,
here in the process transaction function.
Instead of calling process by method,
we now get our processors,
by calling get transaction processor,
and passing the transaction to it.
And now we can simply check if we have a payment
for the given transaction,
in which case, we want to call processors.payment,
and execute this as a function,
and pass the transaction to it,
else we can call processors refund
and pass the transaction as a function.
And of course now we can also outsource this
out of process transaction to keep it clean,
and maybe add a new function here,
which we call process with processor,
accept the transactions argument and copy our code in there.
And now it's processed with processor,
which we can call here.
Though again you can argue
whether this really is a good split or not,
it definitely makes this function more readable,
but now of course we have to scroll down
to process with processor.
Still I would argue both functions are easy to find
and readable and therefore clean.
We could also rename these keys here,
to make it clear that they hold functions,
and rename this to make payment,
and make refund for example, or process payment,
and process refund,
and of course then also use process payment here,
when we store a function,
and process refund when we store a function,
and with these properties renamed,
we can call process refund here,
and process payment here.
But that's just some renaming to make it clear
of what's inside of these properties,
which we of course should do to write clean code.
And now with (indistinct) got rid
of these extra nested if cheques.
Because now we're using such a map of functions,
which we return.
So in the end get transaction processor is a function,
which just returns a map of other functions,
maybe therefore we should rename it
to get transaction processors,
and also call get transaction processors here of course.
Because now this will give us an object
or a map full of functions,
which we then can call
to process the transaction appropriately.
And this is a technique we can use to make this code slimmer
and to remove all these duplicate cheques.