🛠Refactoring: Replacing Conditional with Polymorphism
Tags: programming, polymorphism, objectoriented, goodpractice
Published: 2021-07-26 14:18:23

#### `Switch` statements are often considered code smells and should be avoided
---
## The Problem
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eh382rmot1e2oung00kb.png)
Suppose you have a class with various subtypes defined by a property such as `Bird`:
```cs
public class Bird
{
    // whatever properties do birds have
    public BirdType Type { get; set; }
}

public enum BirdType
{
    African,
    American,
    European
}
```
And then you need to retrieve, lets say, the speed of a given bird. Thing is: the speed of the bird depends of it's type. Some logic is required, but it sounds easy enough right? You create a class method:
```cs
public class Bird
{
    // whatever properties do birds have
    public BirdType Type { get; set; }

    public double GetSpeed()
    {
        switch(Type)
        {
            case African:
                // logic for African birds
            case American:
                // logic for American birds
            case European:
                // logic for European birds
            default:
                // default logic
        }
    }
}
```
A little bit ugly, but it gets the job done right? But here's the catch: after some time in production, you need to add a *new* type of bird, lets say Asian
```cs
public enum BirdType
{
    African,
    American,
    European,
    Asian // new type
}
```
And now you have to calculate it's speed as well. *"Just add another case to the `switch` statement"* you might say. You could do that, yes, but bear in mind that this will violate **SOLID's Open-Closed Principle**! And we don't want that, do we?

---
## The Solution: Polymorphism
With Object-Oriented Programming we have the concept of inheritance and, with that, we can implement polymorphism.

To the uninitiated, polymorphism is the ability to process objects differently depending on their class. Sounds familiar?

How do we approach the above problem with polymorphism in mind? We start very much the same: defining the `Bird` class, but with one change:
```cs
public abstract class Bird
{
    public abstract double GetSpeed();
}
```
Now we have added the `abstract` modifier to the `GetSpeed` method and the `Bird` class itself. What that means is that the `Bird` class itself has no implementation for that method, nor can it be directly instantiated, and any subclasses might implement it themselves. Now all we gotta do is implement the subclasses!
```cs
public class AfricanBird : Bird
{
    public override double GetSpeed()
    {
        // logic for African birds
    }
}

public class AmericanBird : Bird
{
    public override double GetSpeed()
    {
        // logic for American birds
    }
}

public class EuropeanBird : Bird
{
    public override double GetSpeed()
    {
        // logic for European birds
    }
}
```
Let's see how that plays on a running code:
```cs
// Ran on C# Interactive via VisualStudio
> public abstract class Bird
. {
.     public abstract double GetSpeed();
. }
> public class AfricanBird : Bird
. {
.     public override double GetSpeed()
.     {
.         return 1;
.     }
. }
> public class AmericanBird : Bird
. {
.     public override double GetSpeed()
.     {
.         return 0.7;
.     }
. }
> Bird africanBird = new AfricanBird();
> Bird americanBird = new AmericanBird();
> africanBird.GetSpeed()
1
> americanBird.GetSpeed()
0.7
```
Note that as the method we used is declared by `Bird`, we could define the variables as the base class and still use it, and we got our desired result 😉

And what if we need to add a new type of bird? We just add a new subclass! No need to modify any existing class! We have respected the Open-Closed Principle!

* **Note:** This refactor that was done is called **Replace conditional with Polymorphism** (pretty easy to remember the name huh?)

---
## Benefits
* The forementioned compliance with the **Open-Closed Principle**
* Gets rid of duplicate code, as you can get rid of many conditionals and/or switch statements
* Adheres to the **Tell, Don't Ask principle**: the object itself is _telling_ you what you want to know, instead of you having to "ask" (via conditionals) for the information

---
## Reference
* [Martin Fowler's "Refactoring" book](https://martinfowler.com/books/refactoring.html)
* [Refactoring.guru: Replace conditional with Polymorphism](https://refactoring.guru/replace-conditional-with-polymorphism)
* [Switch Statements are like Ants](https://daedtech.com/switch-statements-are-like-ants/)
* [Polymorphism definition](https://www.webopedia.com/definitions/polymorphism/)