JS: Polymorphism
Theory: Strategy (Pattern)
Let's reinforce the theory we've learned with one practical example that shows a typical application of subtype polymorphism.
Imagine the task of calculating the cost of travel insurance. The cost of insurance depends on a large number of factors. Some factors can affect how companies calculate the price by changing the formula itself.
In the case of insurance, there is likely one formula where the values are substituted, and the calculation happens in one go. The main thing for us now is the concept itself, not precise knowledge of the inner workings of the insurance business.
If you solve this problem head-on, it will look like a big mess of calculations with many conditional constructs. Over time, such a code becomes extremely difficult to read because of the many states you keep in mind:
Is there any way to make the code clearer and easier to understand? Sometimes yes. Of all the factors involved in the calculation, you should try to find those that affect it globally. They manifest as a global if at the top level.
Let's assume that in the case of insurance, it's age. We believe that age determines the formula for calculating the cost of insurance.
The next step is to look at the branches in this conditional design and specify the ranges. Let's say it looks like this:
- Under 18
- 18 to 24
- 24 to 65
- Older than 65
There's something important you need to take note of. Above, we agreed that each age group determines the algorithm for calculating the insurance cost. They're independent of each other, although the calculation process itself may be similar in places (and most likely will be).
Now let's move from the logical structure to the code. Each age group is the class responsible for calculating the cost for that group:
The main thing we got was to divide the calculation process into independent blocks of code, which are easier to understand. Each such class is called a strategy (computation).
It's important for the strategy not to be an abstraction, an object with a state and lifetime. Therefore, we pass to the constructor not the data but the method itself.
In essence, it's an ordinary function packed into a class with only one purpose: to get subtype polymorphism. We can do this via the function dispatching by keys to simplify the code.
Next, the following question arises: how and where do we choose the implementation to work with? There are several options here.
We can delegate the choice of implementation to an external code. If we apply dependency inversion, that means we're working with a ready-made strategy:
So far, we've only gotten away from the problem; we haven't solved it. Either way, there will be code somewhere that contains either a conditional construct or implements one of the dispatching methods we covered in previous lessons. In the simplest case, this code would look like this:
As you can see from the examples above, there'll be more code using the strategy, but not as much as if you were to use the dispatching of functions by associative array keys.
It applies to virtually all situations where subtype polymorphism is involved in JavaScript. It is the price you have to pay for a division that simplifies code expansion and reduces its complexity.
On the other hand, it is easy to fall into the trap and, conversely, make the code even more complex than it was before the introduction of subtype polymorphism.
This polymorphism makes the code verbose and overly abstract if applied mindlessly. You don't need expansion as often as people say you do. Moreover, you can invert dependencies as you go along whenever you need to.

