Skip to main content
Blogs

Tech Tip Of The Week: Building A Cleaner Code

By May 26, 2023January 11th, 2024No Comments

Looking to improve the quality of your code?

You’re at the right place.

Are you using If/Else blocks every day? And if your answer is, No man, I write Switch-Cases instead, then let us tell you, they both are quite similar.

The question is, is a code with heavy usage of If/Else blocks good quality? And, does this code comply with SOLID principles?

Take 2 to 5 minutes to observe this C# code see is you find a problem.

public class CallMethodsBasedOnId

{

public void CallRelatedMethod(int id)

{

if (id == 1)

DoSomething();

else if (id == 2)

DoSomethingElse();

else if (id == 3)

DoSomethingDynamic();

else if (id == 4)

DoNothing();

}

 

private void DoNothing()

{

Console.WriteLine(“DoNothing method is called”);

}

private void DoSomethingDynamic()

{

Console.WriteLine(“DoSomethingDynamic method is called”);

}

private void DoSomethingElse()

{

Console.WriteLine(“DoSomethingElse method is called”);

}

private void DoSomething()

{

Console.WriteLine(“DoSomething method is called”);

}

}

In the Program.cs file,

//We’re not talking about DI here, the motive is to show another side of the strategy pattern that’s why a new instance has been used

CallMethodsBasedOnId CallMethodsBasedOnId = new CallMethodsBasedOnId();

CallMethodsBasedOnId.CallRelatedMethod(1);

In the above code, we have a method which calls other methods based on the provided “id.”

Is this something that you encounter in your daily life?

If you still struggling to identify the problem, here is a hint, this code is violating one of the SOLID principles.

The above code isn’t following the Open-Close principle.

How? What will happen when you introduce a new condition say, when “id” is 5 then call the method, DoSomethingFantastic()?

To accomplish this, you need to add a new if condition in CallMethodsBasedOnId.cs as

else if (id == 5)

DoSomethingFantastic();

This stands true for every condition you write with more values of “id”, every time you need to modify the class. It means this class is not closed for modifications.

Now that we’ve understood the problem, what is the solution?

Replace if-else conditions from the code in a way that we do not need to modify the class again.

Interesting. But how?

When there is a violation of SOLID principles there will always be some design pattern to help you out.

The fix is to implement a “Strategy design pattern.”

First, we must understand how strategy pattern works.

By book, it reads “Strategy pattern defines a family of algorithms, encapsulate each one, and make them interchangeable. The Strategy pattern enables a client to choose which algorithm to use from a family of algorithms and gives it a simple way to access it.”

In this pattern (for this particular example), you create a common interface that introduces a method that should align with the return type of your methods being used in your if statements. From our example you can simply figure out for each value of “id” we’ve separate methods those code blocks/events/methods need to be extracted in form of the classes. Each of this class should implement the strategy interface.

Here’s how.

The first place we need an interface like

public interface ICallMethodStrategy

{

void CallMethod();

}

As you can see from the example code, our methods had a return type as “void” as they’re not returning anything to be in line with that, I’ve used the return type as void for CallMethod.

Now we’ve got a parent strategy interface with us and it’s time to break down and separate out all the “if” blocks, when “id==1” we’re calling DoNothing() method, to implement this in strategy pattern you need to take the code from the method DoNothing() and move that to a new class which implements the interface ICallMethodStrategy

public class DoNothingStrategy : ICallMethodStrategy

{

public void CallMethod()

{

Console.WriteLine(“DoNothing method is called”);

}

}

The above code shows what we were talking about.

Do the same for each method we have in the example code. Once done with that, we need to create a class

public class CallMethodsBasedOnIdWithStrategy

{

private readonly Dictionary<int, ICallMethodStrategy> _callMethodStrategy;

 

public CallMethodsBasedOnIdWithStrategy(Dictionary<int, ICallMethodStrategy> callMethodStrategy)

{

_callMethodStrategy = callMethodStrategy;

}

 

public void CallRelatedMethod(int id)

{

_callMethodStrategy[id].CallMethod();

}

}

The above class is injected with a dictionary with the key as int while value as an interface (this is the key, and the interface is the ICallMethodStrategy ) as we’re storing the interface in the dictionary what we could leverage from here is, you can call the CallMethod of ICallMethodStrategy for any given “id”, didn’t get that?

See that in action here, the method CallRelatedMethod of the class is a replica of the method with the same name from “CallMethodsBasedOnId” class, the only difference is, it doesn’t have the if-else statement inside, rather it invokes the method CallMethod() from the dictionary _callMethodStrategy, id paramenter plays the crucial role here and it invokes the correct instance of the class based on the id

Let’s go to the program.cs file and do the following

Dictionary<int, ICallMethodStrategy> _callMethodStrategy = new Dictionary<int, ICallMethodStrategy>

{

{ 1, new DoSomethingStrategy() },

{ 2, new DoSomethingElseStrategy() },

{ 3, new DoSomethingDynamicStrategy() },

{ 4, new DoNothingStrategy() }

};

CallMethodsBasedOnIdWithStrategy CallMethodsBasedOnIdWithStrategy = new CallMethodsBasedOnIdWithStrategy(_callMethodStrategy);

CallMethodsBasedOnIdWithStrategy.CallRelatedMethod(3);

 

Here, for each “id,” we’ve added a concrete instance of all the strategies to the dictionary; this would be injected into the class CallMethodsBasedOnIdWithStrategy to achieve the desired results.

So what we did is in fact we’ve removed the if-else conditions from the code with a cleaner version implemented with the help of a strategy pattern. Now the code is flexible and adding a new id with a new method won’t make you modify your class CallMethodsBasedOnIdWithStrategy you simply have to add a new concrete class implementing ICallMethodStrategy that class needs to be added to the dictionary then with a respected id, that’s all, you have a SOLID compliance code.

Now, a question for you to get your hands on this, what will you do for the “else” condition say if the id is not in 1,2,3 & 4 then CallSomeExceptionMethod? Think about it and you’ll get the answer in the next post.

If you’ve liked the post, please like & share to give us a moral boost.

The entire code for this post is hosted here GitHub – mail2nizamkhan/Patterns.Behavior.Strategy at master

Keep coming for more, thanks for investing your time in reading the post.

Leave a Reply