We are now at the third video of this section factory method where we will be delegating the creation
of different types of payments.
In the previous video we looked at the builder design pattern in this video.
We will implement a payment method factory.
We will create two methods of paying cash and credit card.
We'll also have an interface with the pay method the factory method pattern or simply factory is probably
the second best known and used design pattern in the industry.
Its purpose is to abstract the user from the knowledge of the struct he needs to achieve for a specific
purpose such as retrieving some value maybe from a web service or a database.
The user only needs an interface that provides him this value by delegating this decision to a factory.
This factory can provide an interface that fits the user needs.
It also eases the process of downgrading or upgrading of the implementation of the underlying type if
needed.
When using the factory method design pattern we gain an extra layer of encapsulation so that our program
can grow in a controlled environment with the factory method.
We delegate the creation of families of objects to a different package or object to abstract us from
the knowledge of the pool of possible objects we could use.
Imagine that you want to organize your holidays using a trip agency.
You don't deal with hotels and travelling you just tell the agency the destination you are interested
in so that they provide you with everything you need.
The trip agency represents a factory of trips after the previous description.
The objectives of the factory method design pattern must be clear to you which we have listed here.
Delegating the creation of new instances of structures to a different part of the program working at
the interface level instead of with concrete implementations grouping families of objects to obtain
a family object creator using the previous description.
The requirements for the acceptance criteria are these which you see on your screen to have a common
method for every payment method called pay to be able to delegate the creation of payment methods to
the factory to be able to add more payment methods to the library.
Just by adding it to the factory method.
Now let's move on to the first unit test a factory method has a very simple structure.
We just need to identify how many implementations of our interface we are storing.
Let me open the code file here.
We provide a method get payment method where you can pass a type of payment as an argument.
These lines define the interface of the payment method.
They define a way of making a payment at the shop.
The factory method will return instances of types that implement this interface we have to define the
identified payment methods of the factory as constants so that we can call and check the possible payment
methods from outside of the package.
The highlighted code is the function that will create the object for us it returns a pointer which must
have an object that implements the payment method interface and an error if asked for a method which
is not registered to finish the declaration of the factory.
We create the 2 payment methods.
As you can see the cash PM and the debit card PM struct implement the payment method interface.
By declaring a method pay amount.
Float 32 string the return string will contain information about the payment.
Let's save this file and go back to our factory test Dot.
Go file with this declaration.
We will start by writing the tests for the first acceptance criteria to have a common method to retrieve
objects that implement the payment method interface.
Now we have to separate the tests among a few of the test functions get the payment method is a common
method to retrieve methods of payment.
We use the constant cash which we have defined in the implementation file.
We also check that we have not received an error when asking for a payment method.
Observe that if we receive the error when asking for a payment method we call T dot beetle to stop the
execution of the tests.
If we called just T dot error like in the previous tests we would have a problem in the next lines when
trying to access the pay method of a nil object.
And our tests would crash execution.
We continue by using the pay method of the interface by passing ten dot thirty as the amount the returned
message will have to contain the text paid using cash.
The T dot log method is a special method in testing this struct allows us to write some logs when we
run the tests.
If we pass the hyphen the flag we repeat the same operation with the debit card method.
We asked for the payment method defined with the constant debit card and the returned message.
When paying with a debit card must contain the paid using debit card string finally we are going to
test the situation when we request the payment method that doesn't exist represented by the number 20
which doesn't match any recognized constant in the factory.
We will check if an error message is returned.
When asking for an unknown payment method let us go back to the terminal and check whether all tests
are failing.
Now run this command as you can see in this example we can only see tests that return the payment method
interface interfaces failing in this case we'll have to implement just a part of the code and then test
again before continuing let's jump right into the implementation.
We will start with the get payment method.
It must receive an integer that matches with one of the defined constants of the same file to know which
implementation it should return.
Now open the factory dot go file.
I've already made the changes.
Here's the code which I have added as you can see I have added F.M. T dot Sprint F in the return statement
we use a plain switch to check the contents of the argument and method if it matches any of the known
methods cash or debit card it returns a new instance of them.
Otherwise it will return a nil and an error indicating that the payment method has not been recognized.
Now we can run our tests again to check the second part of the unit tests.
Let's go back to the terminal and execute the same command again.
So these are the messages which are generated after the changes we made.
Now we do not get the errors saying it couldn't find the type of payment methods.
Instead we receive a message not correct error when it tries to use any of the methods that covers.
We also got rid of the not implemented message that was being returned when we asked for an unknown
payment method.
Let's implement the struct now so move on to the factory file and that these lines of code to return
the statement Save the file and navigate to the terminal open the terminal and execute the previous
command again.
We just get the amount printing it in a nicely formatted message with this implementation.
The tests are all passed now.
Also did you see the log messages.
They aren't errors.
We just print some information that we receive when using the package under test.
These messages can be emitted unless you pass the hyphen the flag to the test command.
Let's do it again.
You can see we got the output as pass okay.
We now step ahead to upgrading the debit card method to a new platform.
Imagine that your debit card payment method has changed for some reason and you need a new Struct for
it to achieve this scenario.
You will only need to create the new Struct and replace the old one when the user asks for the debit
card payment method.
This is our new type that will replace the debit card PPM structure.
The debit card PEM implements the same payment method interface as the debit card.
We haven't deleted the previous one.
In case we need it in the future.
The only difference lies in the returned message that now contains the information about the new type.
We also have to modify the method to retrieve the payment methods.
The only modification is in the line where we create the new debit card.
That now points to the newly created struct.
Let's run the tests to see if everything is still correct.
So navigate to the terminal and run the command go test iPhone the iPhone run equal to get payment method
0.
Something has gone wrong.
The expected message when paying with a credit card does not match the returned message.
Does it mean that our code isn't correct.
Generally speaking yes.
You shouldn't modify your tests to make your program work when defining tests.
You should also be aware of not defining them too much because you could achieve some coupling in the
tests that you didn't have in your code.
With the message restriction we have a few grammatically correct possibilities for the message so we'll
change it.
Let's make the changes to the factory don't go file.
Also make the changes to the switch case save the file and move back to the terminal.
Let us run the tests again now.
Everything is okay.
Again this was just a small example of how to write good unit tests to when we wanted to check that
a debit card payment method returns a message that contains paid using debit card string.
We were probably being a bit restrictive and it would be better to check those words separately or define
a better formatting for the returned messages.
Now let's summarize and see what we have learned about the factory method.
So with the factory method pattern we have learned how to group Families of objects to their implementation
is outside of our scope.
We have also learned what to do when we need to upgrade an implementation of a used struct.
Finally we have seen that tests must be written with care.
If you don't want to tie yourself to certain implementations that don't have anything to do with the
tests directly in the next video we will learn about the abstract factory.
Or rather we could say factory of factories.