Single Responsibility Principle

According to the book, the Single Responsiblity Principle states:

"There should never be more than one reason for a class to change."

But what does this means?. Well, translated to simple words this mean that each class should do "one thing", and one thing only. And after this is achieved, that class should never be modified unless there is a "unique reason" to do so.

This does not means that each class should have only one method. The idea behind this is to group things that are functionally related.

Why?

Simple. This principle promotes something called "Separation of concerns". The separation of concerns is basically an organizational concept that allow us to know where each functionality (responsibility) lies and what it does.

Imagine for a second that you can have a "magic" toolbox full of tools for wood working. Which of the following options would you choose?

  • Each tool on your toolbox can have one or many unrelated different functions.
  • Each tool on your toolbox can have one or many related different functions.

If you chose the second, you are on the right path. Each tool should cover one purpose and one purpose only. The same applies to each software module.

For example, your hammer will have 2 uses. One, it can hammer nails into the wood, and second, you can pull the nails out of the wood using the hammer's claws. Although there are 2 functionalities, there is still one purpose, "do wood hammer work", which is the set of those 2 functionalities. Get it?

Let's see an example


public class WoodHammer {
        // Constructor 
        public WoodHammer() 
        {
        }
        // Methods
        public void hammerNailIntoWood() 
        {
            // Hammer time!
        }
        public string pullNailFromWood()
        {
            // come on out you...
        }
}
                    
                

You could, in theory, add another method to this WoodHammer class to, for example, scrape the mud from your shoes. But obviously, this violates the single responsibility principle.

If you added that method to the WoodHammer class you would have something like this..


public class WoodHammer {
        // Constructor  
        public WoodHammer() 
        {
        }
        // Methods
        public void hammerNailIntoWood() 
        {
            // Hammer time!
        }
        public string pullNailFromWood()
        {
            // come on out you...
        }
        public string removeMudFromShoe()
        {
            // yuck...
        }
}
                
            

So what? It works, rigth?

Well yes, it will..but, let's say that 2 months later your boss comes and ask for a new addition to the toolbox..a pneumatic hammer (aka nail gun), also for wood working.

Now, if you try to take advantage of all the functionalities already implemented on the WoodHammer class for your new PneumaticHammer class using inheritance, you will end up having something like this.


public class PneumaticHammer : WoodHammer {
    // Constructor 
    public PneumaticHammer() : base()
    {
        // just call the base constructor ..
    }
    // Methods to do things only pneumatic hammers do..
}
                
            

So..what's wrong here?. The problem is you will add the removeMudFromShoe() method to every PneumaticHammer instance when it's practically impossible to scrape the mud from your shoes with a nail gun.

Also, nail guns don't have claws so your pullNailFromWood() method would be a blatant lie.

How to do it correctly then?

If we follow the principle we have an idea on how to correctly separate each purpose.


public class Hammer {
        // Constructor 
        public Hammer() 
        {
        }
        // Methods
        public void hammerNailIntoWood() 
        {
            // Hammer time!
        }
        
}


public class WoodHammer : Hammer {
        // Constructor
        public WoodHammer() : base()
        {
        }
        // Since we inherit from Hammer we already have the hammerNailIntoWood() 
        // and now we only need to add the pullNailFromWood() since only this 
        // kind of hammer comes with claws to do so.

        public string pullNailFromWood()
        {
            // come on out you...
        }
}

public class PneumaticHammer : Hammer {
    // Constructor 
    public PneumaticHammer() : base()
    {
        // just call the base constructor ..
    }

    // Now this PneumaticHammer only have the functionalities 
    // direcly related to it's behavior.

    // Methods to do things only pneumatic hammers do..
}
                
            

So..what about the removeMudFromShoe() method?

I think you will agree with me that you should not use a hammer to scrape mud from your shoes. The solution would be then to implement your own separate class with the exclusive responsibility to do the scraping

When to change then?

As the principle states, there should be only one reason to change. Let's say that the guy that design an manufacture the wood hammers comes and says, "Hey, you know what? ALL of our wood hammers can be used to straightening nails..so I need to add that functionality.."

Then you can add that straightenNail method to your WoodHammer class knowing that it wont break anything and wont clutter your design.

According to Uncle Bob, there is another way to define this principle, just using different words

Gather together the things that change for the same reasons. Separate those things that change for different reasons.

Basically, try to bundle things (in a class or software entity) that are strongly related, and that will change for the same reason (or have the same responsibility), meaning that the changes will compliment the functionality of that entity/class... and separate those that do unrelated functions into another entitity.