Demystify SOLID: "S" For Single Responsibility Principal

Hi all, I hope all is well, I am fine too. Currently I am concentrating on good design patterns and best practices of application development. If you are an experienced software developer then let me ask one question. How many times have you started to develop a brand new application? And how many times have you started to work in someone's developed application or start to code an existing application?

If my little limited experience comes to my favor then the second one will get more votes. And here is the importance of design patterns and good practices. Experienced developers know the pain of

There are many proven patterns in the software industry and they are just the best fit in certain types of situation. We will not discuss them much but in this article we will understand the SOLID principal of software development.

I would like to present an entire principal with five separate articles. So in this article we will discuss the meaning of “S” in the SOLID principal. The meaning of S is “Single responsibility principal”.

So, in object-oriented programming, the single responsibility principal states that every class should have a single responsibility and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility. The term was introduced by Robert C. Martin in an article by the same name as part of his Principles of Object Oriented Design, made popular by his book Agile Software Development, Principles, Patterns, and Practices.

Let's use an example of the single responsibility principal. Have a look at the following code snippet.

class employeeProcess

{

    public string getName()

    {

        return "Sourav";

    }

 

    public string getEducation()

    {

        return "MCA";

    }

    public string getDesignation()

    {

        return "Developer";

    }

    public void PrintReport()

    {

        Console.WriteLine("Report Printed");

    }

}

We have declares a “employeeProcess” class with a few functions. The function name is very similar with it's activity. Like the getName() function will return the employee name, the getEducation() function will return education and in the same the PrintReport() function will print a report for the specific employee. Fine, pretty simple class design and it will work fine. Oh! But is it really fine?

There is an issue in this design. What is that? We are doing printing activity within the employeeProcess class. As the name suggests the employeeProcess class is built to process only employee data but in this scenario the class involves printing activity.

Now, the problem may arise tomorrow, when our HP printer will not work and we would like to setup this application with one brand new Canon printer, haha..:)

So, the key point is this discussion is, one class will be responsible for one and only one operation. Then we are able to develop for only the de-coupled architecture. So, let's refine the class design.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Data.SqlClient;

using System.Data;

using System.Collections.ObjectModel;

 

namespace FuncTest

{

    class employeeProcess

    {

        public void getName()

        {

            Console.WriteLine("Sourav");

        }

        public void getEducation()

        {

            Console.WriteLine("MCA");

        }

        public void getDesignation()

        {

            Console.WriteLine("Developer");

        }

        public void PrintReport(IPrinter ObjPrint)

        {

            ObjPrint.Print();

        }

    }

 

    interface IPrinter

    {

        void Print();

    }

 

    class HpPrinter : IPrinter

    {

        public void Print()

        {

            Console.WriteLine("Print by HP Printer");

        }

    }

 

    class CompaqPrinter : IPrinter

    {

        public void Print()

        {

            Console.WriteLine("Print by Compaq Printer");

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            employeeProcess Objemp = new employeeProcess();

            Objemp.getName();

            Objemp.getEducation();

            Objemp.getDesignation();

            Objemp.PrintReport(new HpPrinter());

            Console.ReadLine();

        }

    }

}

How have we solved the limitation? Pretty simple, we have just separated the printing mechanism into a different class. We have implemented the de-couple architecture using an IPrinter interface. Currently , we are working with HP and Compaq printers, but tomorrow, if we need to add another printer to our system then we will just add one more class to the application and we will implement the IPrinter interface into it. So our employeeProcess class will be untouched.

The following is the output of the example.

output

So, the key concept is that we will not overload our class with too many tasks. It will be responsible for one and only one task. Sometimes we can see a bad practice, something like, people have implemented a logging mechanism within a class rather than calling to the logging module. Anyway, always try to avoid such kinds of practices.

Conclusion

In this article we learned the “Single responsibility principal” with a suitable example. I believe you will follow this principal at the time of application development. In a future article we will cover all SOLID principals one by one.