Strategy pattern to replace IFs

Daniele Scillia (Dan The Dev)
Dan the Dev
Published in
3 min readApr 9, 2021
Photo by Maarten van den Heuvel on Unsplash

All it takes is an IF

How many times have you heard this? You also know that adding IF without thinking is a failed strategy for the maintenance of our code; today we look for a possible alternative among the Design Patterns.

Design Patterns are a series of abstractions that aim to be solutions to certain problems; they are notout of the box” solutions but more something to adapt to our context and our situation.

Among the design patterns, there are various options that we can use to replace IFs in our codebase, replacing them with a design that allows us to distribute the responsibility of each of the options they handle.

Today we’re going deeper into one in particular: the Strategy Pattern.

The reasons why I chose to explore this pattern are many:

  • I think it is the most understandable and immediate: once understood it is possible to use it in various use cases where we would typically think of an IF
  • it’s semantically coherent and comprehensive: one of the reasons for which it is easy to understand this pattern, in my opinion, is that it is fully described by its name, strategy; something that seems obvious but that in my opinion is not so evident for other patterns
  • it's simple enough: in general, the topic of design patterns is not the easiest to learn; having to choose one, I think that strategy is very immediate, just because it’s quite simple to make concrete examples of use that are quite explicit

First of all, let’s start with a definition: what are design patterns? they are nothing but “standard” solutions to common problems. They are not ready-made “out of the box” but rather solutions to be adapted to your specific situation and context.

Then, what is the problem that Strategy Pattern wants to solve? Simple: let’s suppose we have a logic in which we apply rules/algorithms that can change based on one or more conditions. For example, imagine a Navigator object in which we have only one method, createRoute, that manages both the route by car and the route on foot.

This method becomes a classic example of Bloater code smell because it will grow excessively and for different reasons, having to handle various responsibilities. Not to mention when the public transport route feature will be required, perhaps.

Clearly, our goal is not to have a single method that has responsibility for all possible types of routes; rather, we’d like to isolate each one and then have a method to handle everything else regardless of which type is chosen.

For this we can use the Strategy Pattern, which defines families of algorithms, encapsulating each of them and making them interchangeable.

Screenshot from https://refactoring.guru/design-patterns/strategy

In practice, we could define a RouteStrategyInterface, which would become an attribute of that Navigator class we were talking about before. The class would be instantiated with the strategy needed for the specific case, through dependency injection of the concrete implementation. The createRoute method could then simply invoke the method provided by the interface.

With this refactoring, our method suddenly goes back to having only one responsibility, handling operations let’s say, without knowing exactly what kind of route was chosen and therefore what concrete strategy was passed to it.

--

--

Daniele Scillia (Dan The Dev)
Dan the Dev

Software Engineer @TourRadar - Passionate Dev, XP Advocate, passionate and practitioner of Agile Practices to reach Technical Excellence