Hi everyone.
Welcome back.
So here is our design right.
So we'll start with the payment gateway.
So this payment gateway is going to be a sealed class which is going to have one function named make
payment okay.
So let's go ahead and start with that implementation I'm back in IntelliJ here I'm in the payment package.
So in here I'm going to create a class named Payment gateway.
So in this case create this is going to be payment gateway.
There you go.
So this is our class.
And this class is going to be a sealed class and an abstract class.
Because this is something like a contract where all the different implementations is going to provide
their own implementation.
So and then this is going to be using the permits class as we know the syntax by now, anytime you use
a sealed keyword then you need to make sure you use a permits to allow.
What are the different implementation your sealed class is going to support.
So number one is if you go ahead and take a look at the design here we have debit card payment rewards
card payment and the credit card payment.
So the very first thing I'm going to create a class named debit card payment.
So we can provide debit card payment over here.
This class is not available yet.
Let's go ahead and create this one.
So create class and it's going to be part of the package named payment.
And then press okay.
So the debit card payment extends the payment gateway right.
So that's a deal.
And then anytime you create a subclass for a class what you need to do you need to provide one of the
modifier which should be non-final or sealed.
Or it can be final.
So in this case I'm going to keep it final because I don't want any other class to extend this specific
class which is debit card payment.
So now let's go back to the payment gateway.
All the compilation issues are gone.
So now this abstract class is going to provide an abstract function okay.
So in this case it's going to be public abstract.
And then the function name is going to be make payment okay.
And then this is going to accept the card information and the amount you want to make the payment for.
So in this case it's going to be card.
So we have this card as part of the domain class already.
You can actually go ahead and import that.
And the amount is going to be double.
So in this case double amount I could have used Bigdecimal I just wanted to keep it double to ease our
implementation.
So what this function is going to return.
This is going to return something called payment response.
This enum is already part of the domain package.
If you go here we have two different statuses.
Number one is a success and number is a failure.
Again one another thing to call out is that we are not going to be calling a real time payment gateway
to get this payment completed.
This is still going to be a static response, but the point that I'm trying to make here is that this
lecture is going to provide you an approach to design and implement these kind of use cases.
Okay.
So in here we have this make payment.
Now if we go to the debit card payment class you will be asked to provide an implementation.
So what we will do we'll go ahead and implement that abstract function.
So implement methods.
So make payment.
So this is what we need to implement.
Okay.
So as I mentioned we are actually not going to be calling any real time servers to acquire the payment.
So I'm just going to print out here.
So it's going to be a simple logger message.
So in this case I'm going to provide acquire debit card payment for the amount.
So we shouldn't be printing the card details at any cost.
So I'm going to remove that away.
There you go.
And then the response is going to be payment response dot success.
So it's always going to return success.
But in reality if you have a payment gateway interacting with the actual bank based on what the banking
application response, we will be able to get the real time status for that one.
But with this implementation, it's going to be always success.
So now this is the debit card payment implementation.
So we need to provide the same implementation for the credit card and the rewards card too.
Right.
Because that's what our payment service design is.
So we have the rewards card payment and then the debit card payment.
So in here, in order to keep things simple, what we can do is we can actually copy this and then put
it over here.
And then we can call this one as credit card payment.
So the credit card payment is going to be having its own implementation rights.
But in this case we are just printing the value.
So in this case let's go ahead and change this one to acquire credit card payment.
But the payment gateway class complains about it because this credit card payment is not part of the
permits class yet.
Right.
So in this case we need to add the credit card payment over here.
So once you add that that particular error is resolved.
So this function is going to just print the acquire credit card payment for the amount.
And then the next thing is we need one for the rewards card payment.
So let's go ahead and make a change over there.
So this is going to be rewards card payment.
And then the changes are going to be pretty much the same.
So in here Acquire rewards card payment for the amount.
And then you go ahead and add the rewards card over here.
So in this case it's going to be rewards card payment.
Okay.
So now we have the implementations ready for all the different types of payment or checkout service.
And the payment service supports.
So if you go ahead and take a look at the reference of our design.
So we have the payment gateway class ready, debit card payment ready, rewards card payment ready and
credit card payment ready.
The next step is we are going to implement a factory class based on the card type.
It is going to give you an instance of this appropriate payment instance okay.
So let's go ahead and create the factory class.
So in this case what we are going to do we are going to create the payment factory.
So in this case let's call payment factory.
There you go.
So this payment factory class is a regular class.
And then this function is going to be a static function.
So that is going to be a static function.
And the name of this function is going to be payment gateway okay.
So this is going to accept a card type.
Okay.
So in this case it's going to be card type.
So based on the card type it is going to return the appropriate payment gateway.
So what this return type is going to be it's going to be payment gateway.
What we are implementing is a factory pattern just to call it out so that you know what we are going
to be implementing.
So in this case we can use the enhanced switch.
Right.
Because what we have is a card type.
So the card type is credit.
Then we need to return the credit card payment.
If the card type is debit then we can return the debit card payment.
If the card type is rewards then we can return the rewards card payment.
So we can use the return here.
Because switch is an expression by now you all know that.
So in this case I'm going to pass the card type.
So in the card type.
So if the card is debit.
So in this case we have a debit then it's going to return a new debit card payment okay.
So if the card is credit then it's going to return a new credit card payment okay.
Now if the card is rewards, then in this case it's going to be new rewards card payment.
Okay then end this with semi.
So there is no default block required for this one.
The reason being what we are dealing with is a enum, right?
So if you have a specific enum which just has three different types, then you just need to provide
the implementation for all those supported values.
So this is the exhaustive nature of the enhanced switch I was referring to.
But in this case there is a possibility the card type can still be null.
So we can have a case null.
In the case of this one we can throw an illegal argument exception, and then we can actually provide
the message as card type null not supported okay.
So this is still possible.
It's better to have a null implementation to handle any kind of null pointer exceptions.
So this is our payment factory implementation.
So the payment service is going to be interacting with the payment factory.
So we have completed the payment gateway and the implementation of each and every car type, and then
the payment factor is also completed.
Now let's go ahead and integrate this flow into the payment service.
If you go to the payment service currently, it doesn't deal with any of the classes that we created
yet.
So the very first thing is what we are going to do.
We are going to call payment factory, dot payment gateway.
And then what do we pass to this one.
So in this case we pass the order details dot card dot card type.
So when you pass this what you are going to get is a payment gateway implementation.
Right.
So in this case it's going to be payment gateway.
There you go.
And in here what we are going to do.
So we are going to be returning.
So we can comment this one for now.
Payment gateway dot make payment.
And then you provide the card and the amount.
Right.
So that's what this make payment function accepts.
It accepts a card and the final amount.
So in this case we can get those information from the order details domain class.
So dot card and then order details dot final amount.
There you go.
And then what this is going to respond with.
This is going to respond with a payment response.
So in the in our case, it's always going to be the success because we have some static implementations
of credit card payment, debit card payment and rewards card payment.
All those are returning the payment success okay.
So now if you go to the caller of this function, so the checkout service, once it makes a call based
on the type of the card that's been part of the order details, the appropriate implementation will
be invoked and the response will be sent.
Okay, let me quickly recap what we have done so far.
So anytime the checkout service gets this order details to the checkout order function, it's going
to make a call to the payment service.
And then it's going to call the payment gateway.
So the payment gateway based on the type of the card it's going to provide the appropriate implementation.
So this type of implementation is called a factory pattern because this class acts as a factory of different
implementations based on the input that you provide.
It takes one implementation from the factory and sends that as a response.
So once it's sent to the caller.
So in this case, once the payment gateway is sent which has the appropriate implementation, then we
make a call to the make payment.
And it might go to one of the implementations.
It could be a debit card payment credit card payment or rewards card payment.
And then the appropriate response will be sent back.
Okay.
Now what we are going to do, we are going to write a simple test case to test this behavior.
So there is a test case already available.
So in this case if you go to the checkout service there is a checkout service test class you might be
able to find in the test package.
There you go.
And then in here we can write the test case for this one.
So we have this order details static function based on the card type that you pass.
It's going to randomly create an order details object.
And then it's going to give that as a response.
So what we are going to do is we are going to create a parameterized test over here.
So in this case let's go ahead and add the parameterized test.
And I'm going to add the name equal to checkout for cart type.
And then we are going to be getting the cart type from a enum source.
So in this case it's going to be at enum source and then provide the card type value.
So in this case card Typeclass.
If you provide this information this value will be passed as a input to this test function.
So in this case we can actually provide this value in this format.
What this is going to do is this is going to print the card type value which represents each enum value.
Because if you go and take a look at the card type, we have three different values, right.
We have the credit, debit and rewards, which means this particular test case will be executed for
three different inputs.
And then I'm going to write the function.
It's going to be void checkout.
And then this is where the card type will be passed.
So in this case card type will be passed.
And the source for the card type is coming from this enum source.
Okay.
So the very first thing is we pass the card type to the order detail function.
And this is going to return the order details.
In this case it's going to be order details.
And then we are going to be calling the checkout service, so checkout service is already available
as an instance in this particular class.
And then we call the checkout service dot checkout order and then pass the order details over here.
And if you take a look at the checkout service we have an instance of payment service already passed
to it.
Right.
Because that's needed for the whole orchestration of the flow to start.
So when we call the checkout order from here, what this is going to do, this is going to make the
call to the make payment function.
This doesn't have to be V2.
What I'm going to do I'm going to change this function name to be make payment okay.
And then it makes a call to the gateway gets the appropriate implementation based on the card type.
And then we make the call to the payment function okay.
So now let's go back to the test case.
So from the test case this is always going to give you the success response.
In this case we can actually call this response.
And then we can call Assertequals.
It's going to be checkout status dot success comma response.
So the response is always going to be success rate because we are not making any real time call.
The response is always going to be static.
So now let's go ahead and execute this test case.
So this test case is going to call each and every card type.
So in this case it starts with the credit.
And you can see right in the logger we have the acquire credit card payment for the amount 99.
And we have for the debit we have the acquired debit card payment.
This means the debit card implementation is invoked right.
Because that's what this particular logger is coming from.
And then the next one is the rewards.
So rewards is again it's coming from the reward card implementation.
There we go.
So the payment factory class acts as an entry point.
So based on the card type it's going to return you the appropriate instance.
And that particular instance will be invoked.
So we wrote our test case that actually test all the behavior that we have expected to work.
I hope you all have a pretty good idea about how this whole implementation works.
If you have any questions, please go ahead and write it in Q&A.
I would be happy to help.
This marks the end of this lecture.
Thank you for watching.