Design Patterns with Typescript: Strategy
I really want to explain Design Patterns in my own words. As Albert Einstein said:
If you cannot explain it simply, you don’t understand it well enough. — Albert Einstein
So, let’s try to explain Design Patterns simply and in my own words with some examples in Typescript, a coding language that I’m working on more nowadays.
Let’s see this Design Pattern called Strategy.
Why Design Patterns?
Software engineering is a hard field with a lot of problems. Those architectural problems probably were already solved by someone and there is a guide to follow which we call “Design Patterns”.
The point is: don’t try to recreate a solution that already exists. Be smart! Learn with the previous “generations” and create something better, based on previous knowledge, for the next generations. That’s how Software Engineering will evolve.
Learn from previous solutions, create better systems, leave a bigger legacy for the next Software Engineers.
We should stand on the giant’s shoulders!
The problem
Let’s imagine that your application is responsible to process payments. The goal of processing a payment is pretty simple, we should charge the client. However, there are some ways to do that like:
- Credit Card
- Debit Card
- Billet
- Automatic Charge in your bank account (like GoCardless)
- Bitcoin
- And it goes on…
So, we have different ways to charge a client. In that case, we have algorithms that do the same thing in different ways. In a part of their code, they are different, but their goal is the same, which is to charge the client.
How can we solve this? Well, we could have one simple class that will process the payment with different methods. But that would bring a lot of responsibilities for the same class, which doesn’t follow the Single Responsibility Principle (SRP) or even Open Closed Principle (OCP), since we should change the Payment class for each new way to charge the client.
Therefore, how to solve this elegantly?
Strategy
The way we can solve this is using the Strategy Design Pattern, which is a behavioral design pattern. This class will receive the “strategy” to achieve this objective. So, that fits so well in our example. We want to charge clients in different ways.
To apply the strategy pattern we are going to have:
- One interface structuring the way the strategies must work
- One strategy class, which will call this specific method from the given strategy
- Multiple classes to do the same thing in such a different way
Let’s dive deeper into the TypeScript code.
Types and Interfaces
Here we are going to define the structure that the strategies should follow. We consider a strategy the class that will do the same thing differently. So, this interface will be the contract between all strategies:
Here we have a Payment type and the interface has just one single method: charge(), which should return a Payment.
That’s easy! Let’s check the different ways to charge a client and how they must follow this interface.
Charging with Debit card and Credit card
Here we should define the classes that will do the same thing in different ways. The same thing: charge the client. The different ways: one will do it by a credit card, the other one will do it by a debit card.
They will look like this:
Each one implements the PaymentMethod interface, that’s why they both should have the charge() method. There are a lot of benefits by doing this:
- Each class has its own business rules to do the same thing (Separation of Concerns).
- Each class has its own responsibility (Single Responsibility Principle).
- It’s easy to extend. If there’s another way to charge the client, we just need to create a new class implementing the PaymentMethod interface. That totally follows Open Closed Principe (OCP).
As you can see, this is an elegant way to split the responsibilities. However, how are they going to work? That’s why we are going to see the next class: the PaymentStrategy.
PaymentStrategy
This is going to be a class where we can set up the strategy that we are going to use at that moment. We have different ways to do the same thing, but which one should we use? The strategy receives it!
So now we are totally able to set up the strategy that we want to use:
What if we want to use the debit card strategy? That’s easy!
Conclusion
Now we know an elegant solution to do the same thing in different ways. And that’s called: Strategy Design Pattern.