Dot Net For All

Single Responsibility Principle implementation with use cases

Hello Friends, in one of my previous article I have explained about all the SOLID principles with examples. But we need to go through more and more code examples to understand about the implementation of these principles. In this article I will cover the single responsibility pattern in more depth. This article will provide you one more anchors to have a deep understanding of it.

Cohesion and Coupling

To understand the single responsibility principle, let understand these two terminologies. Cohesion and coupling.

Cohesion:

As per google, the meaning of cohesion is “the action or fact of forming a united whole.”.

But when it comes to the software terminology, Cohesion is the degree to which various parts of software components are related.

Lets try to understand it with the help of real life example. Below are the two images of the garbage. The first image shows the unsegregated garbage, its difficult to identify the different type of bottles present. It becomes a headache for the person who is planning to segregate and dump it.

On the other hand, in the second image the the bottles are identified and segregated properly in their bins. The garbage in second image is highly cohesive. The bottles in the second image have common relation, they are all made of same material in the same bin.

That’s why the degree of the unsegregated waste have low cohesion and the degree of the cohesion is high in segregated waste.

Low and High Cohesion

Let try to understand the cohesion in the code example. In the below code, we have four methods. You can guess their functionality from their names. What do you think about the cohesivity of the below class.

Cohesion in code

The methods CalculateArea and CalculatePerimeter are closely related as they deal with the measurements of the square. Their is high level of cohesion among these methods.

The methods Draw and Rotate deal with the rendering of the square image on the screen. There is high degree of cohesion among these two methods as well.

But if we take all the methods, the level of cohesion is low. For example, the CalculatePerimeter is totally different from the Draw method as they deal with totally different responsibilities.

public class Square
    {
        public int Side { get; set; }

        public bool IsHighResolutionMonitor { get; set; }

        public int CalculateArea()
        {
            return Side * Side;
        }

        public int CalculatePerimeter()
        {
            return Side * 4;
        }

        public void Draw()
        {
            if (IsHighResolutionMonitor)
            {
                //Render a high resolution of the Image
            }
            else
            {
                //Render a low resolution of the Image
            }
        }

        public void Rotate()
        {
            //Rotate the image of the sqaure clockwise and re render
        }
    }

To increase the level of cohesion, we should segregate the code based on the responsibilities. I have create a new class named as SquareUI and it mainly deal with the rendering and drawing of the square.

Below classes follow one aspect of the single responsibility principle. Therefore these classes are highly cohesive or they are doing highly related tasks.

If there is high cohesion among the methods of the class, we can assign single responsibility to the class as a whole.

For the first class square, the responsibility of this class is to deal with the measurements of a square. Similarly, the responsibility of the SquareUI class is to deal with the rendering of the share.

   public class Square
    {
        public int Side { get; set; }

        public int CalculateArea()
        {
            return Side * Side;
        }

        public int CalculatePerimeter()
        {
            return Side * 4;
        }
    }

    public class SquareUI
    { 
        public bool IsHighResolutionMonitor { get; set; }
        public void Draw()
        {
            if (IsHighResolutionMonitor)
            {
                //Render a high resolution of the Image
            }
            else
            {
                //Render a low resolution of the Image
            }
        }

        public void Rotate()
        {
            //Rotate the image of the sqaure clockwise and re render
        }
    }
}

Aiming for higher cohesion helps us to move towards single responsibility principle.

Coupling

Coupling is defined as level of interdependency between various software components.

Before proceeding further lets look a code snippet. In the below code you can see we have student class and it exposes some properties. Along with that it also serialize the class and saves it into the MsSQL DB.

After some time you want to save the data into mySQL DB or some no sql DB like DynamoDB. It means you have to change the method in the class.

Therefore you can say that the functionality of saving the data is tightly coupled with the Student class. However, Student class should be contained only to carry the details of the student.

The student class should not be dealing with low level details of dealing with database.

public class Student
    {
        private int studentID;
        private DateTime studentDOB;
        private string address;

        public void Save()
        {         
            String objectStr = JsonConvert.SerializeObject(this);
            SqlConnection conn = new SqlConnection();
            conn.ConnectionString = "Data Source=YourServerName;" +
                  "Initial Catalog=YourDBName;" +
                  "Integrated Security=SSPI;";

            conn.Open();
            SqlCommand command = new SqlCommand(string.Format("INSERT Into Student Values ({0})", objectStr));
            conn.Close();

        }

        public int StudentID
        {
            get { return studentID; }
            set { studentID = value; }
        }

        public DateTime StudentDOB 
        {
            get { return studentDOB; }
            set { studentDOB = value; }
        }

        public String Address
        {
            get { return address; }
            set { address = value; }
        }

    }

We can solve this problem by creating a StudentRepository class and hand over the database save part to the class.

Reason for change

As per single responsibility principle, every software component should have one and only one reason to change. Uncle Bob or Robert Martin says so in his book.

If you are already in the software development, you should already know that software keeps changing.

If our class has multiple reasons to change, than the frequency of change will increase. Therefore increasing the chances of introducing the bugs in the software. Finally resulting in the increased cost of development and testing.

As we can see from the previous example of Student class. There are many reasons to changes. One of them is to change the Database implementation.

We can eliminate this reason by creating a new class which handles the database operation only.

Conclusion

Single responsibility principle deals with the simplification of the Class. it always recommends high cohesion and loose coupling. And there should be minimum reason to change for the class.

Cohesion is the degree to which the various parts of a software component are related.

Coupling is defined as the level of inter dependency between various software components.

Top career enhancing courses you can't miss

My Learning Resource

Excel your system design interview