Last week I covered the Single Responsibility Principe, which is part of the SOLID Principles, this week I will continue and cover the next principle  which is the Open/Closed Principle.

What is The Open Closed Principle?

Robert “Uncle Bob”  Martín, defines it like this:
The open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behaviour to be extended without modifying its source code.

Simply stated, this means that we should not have to change our code every time a requirement or a rule changes. Our code should be extensible enough that we can write it once and not have to change it later just because we have new functionality or a change to a requirement.

Imagine what life would be like if every new feature or requirement resulted in changing the source code, that would mean that one has to  test the code again and again, that would be a tedious thing, lest to say boring.

*Code Example

Let me illustrate with a code example

Background

 We were working on a project where we were using Oracle as the prime repository until one fine day our technical lead came up and announced that our application should support SQL Server as another data source.

Now our Data access layer had a DBConnection class with a connect method strongly bound to accept Oracle provider and establish a connection.

I ignored the detailed implementation and tried to keep things simple.

Initial Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    class DBConnection
    {
        public void Connect(OracleProvider ora)
        {
            Console.WriteLine("Connected to oracle data source");
        }
    }

    class OracleProvider
    {
        string _providername;
    }
}

As we were in a hurry for the delivery, we could only come up with this design for the existing dbConnection class so that it now supports SQL provider too.

After Refactoring

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    class DBConnection
    {

        public void Connect(object o)
        {

            if (o is OracleProvider)
            {
                Console.WriteLine("Connected to oracle data source");
            }
            else if (o is SQlProvider)
            {
                Console.WriteLine("Connected to sql data source");
            }
        }
    }

    class OracleProvider
    {
        string _providername;
    }

    class SQlProvider
    {
        string _providername;
    }
}

OMG ! We designed something wrong …

Here if you can see from the above code, we are modifying the class DBConnection rather than extending it by including if else statements, this simply is against OCP.

Reason is simple if tomorrow another provider is introduced, again we have to make changes to the DBconnection class.

Ultimate refactoring …

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    interface IDBConnection
    {
        public void Connect();
    }

    class DBConnection
    {
        public void Connect(IDBConnection con)
        {
            con.Connect();
        }
    }

    class OracleProvider :IDBConnection
    {
        string _providername;

        public void Connect()
        {
            Console.WriteLine("Connected to oracle data source");
        }        
    }

    class SQlProvider:IDBConnection
    {
        string _providername;

        public void Connect()
        {
            Console.WriteLine("Connected to sql data source");
        }        
    }
}

Finally the main method ….

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    class Program
    {
        static void Main(string[] args)
        {
            //Sql connection 
            IDBConnection conSQl = new SQlProvider();
            conSQl.Connect();

            //oracle connection 
            //IDBConnection conOra = new SQlProvider();
            //conOra.Connect();
        }       
    }
}

The above design we could come up seems to adhere to OCP.
Now tomorrow if we have to support another Data source, we can easily do it by simply extending IDBConnection needless to make any changes to DBConnection.

So the entities are now open for extension and closed for modification.

That’s it for this week, will be looking at the the Liskov Substitution Principle next,which is the letter “L” in the SOLID Principles acronym.

*Code example adapted from an article in code project
%d bloggers like this: