So let's review where we stand.
We've got this interface which has two methods process and refund payment.
We've got an abstract base class that will just handle some common functionality of our payment processors.
It accepts an API key for example, and it implements currently empty.
Those two interface methods.
And then we've got those two concrete classes which extend the base class.
So previously I've said that we might implement some common functionality.
And this is what I'd like to do.
But first let's introduce abstract methods that we just explicitly define.
And this one would be protected.
So accessible in this and the child classes.
So this would be validate API key.
This would be a boolean.
So it's like in an interface.
When a method is abstract, it's not implemented.
It's supposed to be implemented by a class that extends this one.
Aethes.
Now I can actually use this method inside this class.
So I can actually call this validate API key method even though it's declared abstract.
Now how is that possible.
So here first let's throw an exception.
So we haven't talked about exceptions yet.
This basically stops the program execution.
So we're going to cover this a little bit later.
And this is how you throw an exception using a throw keyword.
So going back to this method I can call it even though it is marked as abstract.
The reason is eventually for everything here to make sense, I need a concrete class and only then I
can create such class and concrete class cannot have any abstract methods.
This means that those classes that extend the base online payment processor.
They need this method implemented Rlhs.
So in this case here, when the validate API key is being called, this would actually run a concrete
implementation of that method from a child class.
Now the refund payment method can contain the same logic.
So it validates the API key first.
So now we can or we have to actually implement this abstract method in the child classes.
So we've got these two child classes here.
And if they are not to be abstract they need to implement this abstract method.
So let's do it right now.
Let me copy the header of this and provide the actual implementation here and here.
And this is no longer an abstract method.
So first let's validate the key for stripe.
So this could be something simple like we're gonna use stripe pause.
To make sure that inside the API key it starts with an src prefix.
And we're just gonna check if the position of this string inside API key is zero, which basically means
API key starts with src underscore.
And PayPal can have different rules in here.
So in this case we're going to check if the length of this API key equals exactly 32.
Now at this point I think we should see this in action.
But before we do those methods they require a return value which is a boolean.
So for now let's just return true for both of them.
And then we're gonna see how can we have some specific implementation of how those operations should
be performed.
So here we can see that we are creating a stripe processor.
So this means we should be able to call process payment and see if it works.
So let's process our payment of 500 and let's run it.
So we see a fatal error.
So as I said throwing an exception is a way to trigger fatal error manually, and it is our error message
that it is an invalid API key.
So as you see the method process payment, which is implemented in a base class in the parent class
that's online payment processor has actually called an implementation of validate API key from the stripe
processor.
And I can confirm that because looking at the requirements here, it has to start with src underscore.
And currently it is just key underscore.
And if I change this to be what stripe requires now everything is fine.
Now at this point let's ask a question.
Why would we need an interfaces at all?
If it seems that we can have the same functionality with an abstract class, and more Because the abstract
class can actually implement something.
So let's see an example.
I can make an abstract class called payment processor.
And just define those methods as being abstract.
And now every class that extends this payment processor class would have to implement those methods.
So here's the first limitation of using an abstract class.
The way we just used interface classes can only extend one single class while they can implement multiple
interfaces.
So if we try to ignore this and just put everything inside the online payment processor, then we can
quickly run into things that can't really be solved like with this online payment processor.
We are accepting an API key, assuming that the payment processors are some kind of services with which
we need to connect, and we need a key.
Now, if we would like to use the same methods to process payment and refund a payment, but this time
with cash, then the abstract class seems to not really fit what we require.
Because with cash you don't really have any services nor API keys.
So that's why interfaces really have their purpose.
So let's see an example of such a cash payment processor.
So I would define a cash payment processor.
And this would directly implement the payment.
Processor.
So an interface.
And from the interface we can just copy those methods and do whatever.
We are not really worrying about the actual logic in this examples.
Okay.
So let's return true from those methods.
And here maybe we can actually say that we process cash.
That would be cash refund and cash payment.
Now if we then go back to our abstract class, we can see that what happened here is by implementing
the interface and initially implementing some common logic for process, payment and refund payment
methods.
We actually have no way of making sure that the stripe processor or PayPal processor contain any specific
logic, so we can leverage the abstract methods to enforce that.
So let me copy the header of process payment and just create an abstract protected function that can
be called maybe execute payment.
And it's going to have the same headers and another one that will be execute refund.
Now we have two additional abstract methods that have to be implemented in every single child class
of this online payment processor.
Essentially, this means that these methods have to be implemented in stripe and PayPal payment processors.
Now we are going to actually call those methods inside the online payment processor.
So in the process payment we're going to return the result of this execute payment passing the amount.
And with the refund payment.
We're going to do the same.
But just calling execute refund.
So we just use specific designs in this example so that if anyone would like to or would need to create
some other specific payment processor, they don't really have to worry about a lot of things because
they have an interface.
They need to adhere to a contract.
And additionally there is an abstract class which has some predefined way of how things should be running.
So with this payment processor interface and then with online payment processor abstract class, we
actually show the way for ourselves, our team and all the future developers how things should be done
in our program.
So if you need a payment processor that needs to have some specific logic, is cash, or uses something
that's just not online, you simply implement the interface.
That's the most generic description of what features such payment processing system needs to provide.
But then we have a little bit more specific requirements for an online payment processor.
So it's still implements an interface, but then additionally requires all the child classes to implement
some specific functionality, and also calls this functionality so that if you need another online payment
processor, you just know you need to implement those three methods and then you don't worry about anything
else.
Okay, so I think this is quite some material to digest.
That's why I think we should take another break.
And in the final third episode about interfaces and abstract classes, we're gonna see how can we use
all of those classes.
And we're gonna summarize what benefits do interface and abstract classes give us in software engineering?