If Statements Vs Object Oreiented practices
When i was browsing, i found that there is a campaign called "The Anti If Campaign" https://www.antiifcampaign.com/code-recruitment.html. They are very much related to the Agile team. I read saw a claim that says the "IF Statements" are difficult to maintain and to add/delete codes inside them. They claim to use inheritance and Object Oriented best practices to enhance the code.
So i said to myself how can that impact performance? Then i decided to create this example:
Let’s take it step by step
if i have two products A & B
A comes in three flavors C, D & E.
C comes in three flavors too F, G & H.
so when you come to the bottom of it, you see that there are actually 6 products. C, D, E, F, G & H.
The If-Statement-Way
If i have a code that will simulate that scenario, it would be like this:
if( a == 1)
{
if (b == 2)
{
if (c == 3) doSomething(a, b, c);
else if (c == 4) doSomething(a, b, c);
else doSomething(a, b, c);
}
else if (b == 3) doSomething(a, b, c);
else doSomething(a, b, c);
}
else doSomething(a, b, c);
The Anti-If-Way
If you follow the people who are "Anti IF Statement", i would write the code in a different way:
public abstract class MyBaseClass
{
public int a, b, c;
public MyBaseClass() { }
public abstract void doSomething();
}
public abstract class AEqual1Class : MyBaseClass
{
public AEqual1Class() {a = 1;}
}
public abstract class BEqual2Class : AEqual1Class
{
public BEqual2Class(){b = 2;}
}
public class CEqual3Class : BEqual2Class
{
public CEqual3Class(){c = 3;}
public override void doSomething(){…}
}
public class CEqual4Class : BEqual2Class
{
public CEqual4Class(){c = 4;}
public override void doSomething(){…}
}
public class CEqualOtherClass : BEqual2Class
{
public CEqualOtherClass() {c = 100;}
public override void doSomething(){…}
}
public class BEqual3Class : AEqual1Class
{
public BEqual3Class(){b = 3;c = 100;}
public override void doSomething(){…}
}
public class BEqualOtherClass : AEqual1Class
{
public BEqualOtherClass(){b = 100;c = 100;}
public override void doSomething(){…}
}
public class AEqualOtherClass : MyBaseClass
{
public AEqualOtherClass(){a = 100;b = 100;c = 100;}
public override void doSomething(){…}
}
The Results
So i decided to compare between the two methods in all cases by calculating the execution time of each one and below are the results:
Test |
in case of IF statements |
in case of *NO* IF statements |
a=100, b=100, c=100 |
1.00619492645912 seconds |
0.499456347674696 seconds |
a=1, b=100, c=100 |
0.333323067994865 seconds |
0.249895601507773 seconds |
a=1, b=3, c=100 |
0.200379324787097 seconds |
0.166854522360645 seconds |
a=1, b=3, c=100 |
0.142798249143871 seconds |
0.125212235872841 seconds |
a=1, b=3, c=4 |
0.111325223259706 seconds |
0.10132541944173 seconds |
a=1, b=2, c=3 |
0.0910784876580769 seconds |
0.0835666302589329 seconds |
To be honest the results came us a surprise to me J. But I’ve learned something today.
Updated --- some people wanted to get the test project
Test Project
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AntiIfStatements
{
class Program
{
static void Main(string[] args)
{
QueryPerfCounter counter = new QueryPerfCounter();
// Calculate time per iteration in nanoseconds
double result;
counter.Start();
counter.Stop();
Console.WriteLine("in case of IF statements a=100, b=100, c=100");
counter.Start();
IIfStatements(100,100,100);
counter.Stop();
result = counter.Duration(1);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of *NO* IF statements a=100, b=100, c=100");
counter.Start();
NoIfStatement(new AEqualOtherClass());
counter.Stop();
result = counter.Duration(2);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of IF statements a=1, b=100, c=100");
counter.Start();
IIfStatements(1, 100, 100);
counter.Stop();
result = counter.Duration(3);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of *NO* IF statements a=1, b=100, c=100");
counter.Start();
NoIfStatement(new BEqualOtherClass());
counter.Stop();
result = counter.Duration(4);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of IF statements a=1, b=3, c=100");
counter.Start();
IIfStatements(1, 3, 100);
counter.Stop();
result = counter.Duration(5);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of *NO* IF statements a=1, b=3, c=100");
counter.Start();
NoIfStatement(new BEqual3Class());
counter.Stop();
result = counter.Duration(6);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of IF statements a=1, b=2, c=100");
counter.Start();
IIfStatements(1, 3, 100);
counter.Stop();
result = counter.Duration(7);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of *NO* IF statements a=1, b=2, c=100");
counter.Start();
NoIfStatement(new CEqualOtherClass());
counter.Stop();
result = counter.Duration(8);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of IF statements a=1, b=2, c=4");
counter.Start();
IIfStatements(1, 3, 4);
counter.Stop();
result = counter.Duration(9);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of *NO* IF statements a=1, b=2, c=4");
counter.Start();
NoIfStatement(new CEqual4Class());
counter.Stop();
result = counter.Duration(10);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of IF statements a=1, b=2, c=3");
counter.Start();
IIfStatements(1, 3, 3);
counter.Stop();
result = counter.Duration(11);
Console.WriteLine(result / 1000000000 + " seconds");
Console.WriteLine("in case of *NO* IF statements a=1, b=2, c=3");
counter.Start();
NoIfStatement(new CEqual3Class());
counter.Stop();
result = counter.Duration(12);
Console.WriteLine(result / 1000000000 + " seconds");
Console.ReadLine();
}
static void IIfStatements(int a, int b, int c)
{
if( a == 1)
{
if (b == 2)
{
if (c == 3) doSomething(a, b, c);
else if (c == 4) doSomething(a, b, c);
else doSomething(a, b, c);
}
else if (b == 3) doSomething(a, b, c);
else doSomething(a, b, c);
}
else doSomething(a, b, c);
}
static void doSomething(int a,int b,int c)
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);
}
static void NoIfStatement(MyBaseClass MyClass)
{
MyClass.doSomething();
}
}
public abstract class MyBaseClass
{
public int a, b, c;
public MyBaseClass() { }
public abstract void doSomething();
}
public abstract class AEqual1Class : MyBaseClass
{
public AEqual1Class() {a = 1;}
}
public abstract class BEqual2Class : AEqual1Class
{
public BEqual2Class(){b = 2;}
}
public class CEqual3Class : BEqual2Class
{
public CEqual3Class(){c = 3;}
public override void doSomething()
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);
}
}
public class CEqual4Class : BEqual2Class
{
public CEqual4Class(){c = 4;}
public override void doSomething()
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);
}
}
public class CEqualOtherClass : BEqual2Class
{
public CEqualOtherClass() {c = 100;}
public override void doSomething()
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);
}
}
public class BEqual3Class : AEqual1Class
{
public BEqual3Class(){b = 3;c = 100;}
public override void doSomething()
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);
}
}
public class BEqualOtherClass : AEqual1Class
{
public BEqualOtherClass(){b = 100;c = 100;}
public override void doSomething()
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}", a, b, c);
}
}
public class AEqualOtherClass : MyBaseClass
{
public AEqualOtherClass(){a = 100;b = 100;c = 100;}
public override void doSomething()
{
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine("\tvalues a={0}, b={1}, c={2}",a,b,c);
}
}
}