I am struggling to understand how the Single Responsibility Principle can me made to work with OOP.
If we are to follow the principle to a tee, then are we not left with many classes, many of which may just have one method each?
If we don't follow the principle exactly, then what is the point in the principle?
A class shall handle one topic, that's its single responsibility. A class
Car
could contain methods likestartEngine()
or attributes likeweight
:Of course you can break up this class more. For example by defining a class for the engine:
But you shall not define seperate classes for starting and stopping the engine like:
The principle says to break up classes as reasonable as possible to achieve abstractness. Abstracting too deep violates this principle.
Single Responsibility term was introduced by Rober C. Martin. Main motto of this principle is a reason to change. A class or module should have one, and only one, reason to be changed.The major benefit of this principle is that is makes the class more robust. Changes in one class or module doesn't break the other part.
It prevents an object from becoming a God Object that is an example of Anti-Pattern. It also prevents from Ravioli code (A source code with lots of tiny, tightly-coupled objects).
Hence, Single responsibility principle is an important part of good source code design in OOP.
This is one of the common misunderstanding of Single Responsibility Principle that a class should have only one function. A class is responsible for only one thing doesn't mean a class should have only one function. Single Responsibility Principle means logically separate your functionality into different classes instead of mixing up things.
One very simple example is, say if you are creating a Calculator you can add all functionalities purely for the calculator in the same class (add, subtract, multiply, divide etc.). You don't need to create a separate class for each of the functionality of calculator. But if you want to print calculated result to a printer then don't write the logic of printing to printer inside calculator class because printing to the printer is not the responsibility of calculator class. Create a separate class for the printer and write printing related logic in that class. If you are writing printing functionalities inside Calculator class then you are violating Single Responsibility Principle.
Before you go into decomposing responsibilities, you should have an idea on what the class is supposed to do. It's supposed to do that thing and only that thing as Matt mentioned in his answer. Implement that idea in the simplest way possible just to make it work. That's when you go about decomposing the code you wrote into responsibilities.
The important thing to consider when you break down your code is to make sure that it is readable after breaking it down.
I tend to think of the Single Responsibility Principle (and really a lot of the rules of thumb, patterns, and models) as a general way of thinking about problems. It's meant to guide you toward improvements to your code, but not necessarily prescribe exactly what a solution looks like. Because ultimately software design is a wicked and subjective problem.
I don't think that SRP should always lead to a bunch of single function classes. Though these may sometimes occur if you have some complex logic that you want to abstract away. In general, though, you should trend toward classes with highly cohesive functionality where methods:
Are all related to the same abstraction(s)
Share common dependencies
All operate at the same level of abstraction
You actually want to try to group as much functionality as you can, while maintaining the above conditions and keeping in mind how understandable your abstraction is. Ultimately the goal of the Single Responsibility Principle is to help manage complexity and make the code more understandable.
I quote Robert C. Martin from his book Clean Code: