Refactor a Switch Using OOP Techniques

Refactor a Switch Using OOP Techniques

Making cleaner switch statements.

You can check all the code in this git repository.

Have you ever had a switch like this:

switch (operation)
{
    case "+":
        Add(number, number2);
        break;
    case "-":
        Subtraction(number, number2);
        break;
    case "*":
        Multiply(number, number2);
        break;
    case "/":
        Divide(number, number2);
        break;
    default:
        break;
}

And what about this code:

var calculator = CalculatorFactory.CreateCalculator(operation);
double result = calculator.Calculate(number, number2);

Both snippets solves the same problem, which one do you think it’s better to maintain and read?

The Problem

Switch statements can cause problems. First problem is readability, big code’s blocks are hard to read, so if you find yourself scrolling to see all the switch code, maybe it’s time for a refactoring.

The other problem is duplication, many times in a project we end up writing the same switch more than once. Each time that we make a change in a switch, we have to update all the other ones, this is pain and prone to bugs on the system.

To make ours lives better instead of using a switch, we can refactor to use proper classes with object-oriented techniques.

Example

For this example I’m gonna use the first switch that showed on the post.

switch (operation)
{
    case "+":
        Add(number, number2);
        break;
    case "-":
        Subtraction(number, number2);
        break;
    case "*":
        Multiply(number, number2);
        break;
    case "/":
        Divide(number, number2);
        break;
    default:
        break;
}

This is a code’s snippet of a console application, in which, we’re implementing a basic calculator. We enter two numbers and the operation.

The Solution

The first thing in the refactoring is to create a factory class.

public static class CalculatorFactory
{
    private static readonly Dictionary<string, Func<ICalculate>> CalculatorMap = new Dictionary<string, Func<ICalculate>>
    {
        { "+", () => new Add() },
        { "-", () => new Subtract() },
        { "*", () => new Multiply() },
        { "/", () => new Divide() },
    };

    public static ICalculate CreateCalculator(string operation)
    {
        return CalculatorMap[operation]();
    }
}

This class has a dictionary, CalculatorMap<string, Func<ICalculate>>, in which, the key is representing the operation and the value is a function that will execute the operation. 

And we need a method to return the right from function from the dictionary, called CreateCalculatorFromOperation. This method will return the calculator instance based on the operation.

Also, I’ve created an interface, ICalculate:

public interface ICalculate
{
    double Calculate(string number, string number2);
}

This interface has a method Calculate and all operations will inherit it. Each operation implements this interface, such as:

public class Add : ICalculate
{
    public double Calculate(string number, string number2)
    {
        return double.Parse(number) + double.Parse(number2);
    }
}

The Add class implements the Calculate method from the ICalculate interface. All other calculator operations implement _ICalculate _in the same fashion.

Now that we set up all the structure, we can use the calculator:

var calculator = CalculatorFactory.CreateCalculator(operation);
double result = calculator.Calculate(number, number2);

The usage is simple, we call the CreateCalculator method from the CalculatorFactory class, passing the operation as the argument, to return the calculator instance. After that, we call the Calculate method and get the result.

Conclusion

In conclusion, in this post I showed one way to refactor a switch using object-oriented techniques, there are ways other to make this refactor, but, I think this is the simplest one.

We address the problems that were point out in the beginning, regarding code’s duplication and readability, by isolating the switch’s logic in a separated class.

You can check all the code in this git repository.

Further Reading and References


© 2021. All rights reserved.

Powered by Hydejack v9.1.6