SOLID – How a Class Can Have Multiple Methods Without Breaking the Single Responsibility Principle

single-responsibilitysolid

The Single responsibility principle is defined on wikipedia as

The single responsibility principle is a computer programming principle that states that every module, class, or function should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class

If a class should only have a single responsibility, how can it have more than 1 method? Wouldn't each method have a different responsibility, which would then mean that the class would have more than 1 responsibility.

Every example I've seen demonstrating the single responsibility principle uses an example class that only has one method. It might help to see an example or to have an explanation of a class with multiple methods that can still be considered to have one responsibility.

Best Answer

The single responsibility might not be something that a single function can fulfill.

 class Location { 
     public int getX() { 
         return x;
     } 
     public int getY() { 
         return y; 
     } 
 }

This class may break the single responsibility principle. Not because it has two functions, but if the code for getX() and getY() have to satisfy different stakeholders that may demand change. If Vice President Mr. X sends around a memo that all numbers shall be expressed as floating point numbers and Accounting Director Mrs. Y insists that all numbers her department reviews shall remain integers regardless of what Mr. X thinks well then this class had better have a single idea of who it's responsible to because things are about to get confusing.

If SRP had been followed it would be clear if the Location class contributes to things Mr X and his group are exposed to. Make clear what the class is responsible to and you know which directive impacts this class. If they both impact this class then it was poorly designed to minimize the impact of change. "A class should only have one reason to change" doesn't mean the entire class can only ever do one little thing. It means I shouldn't be able to look at the class and say that both Mr X and Mrs Y have an interest in this class.

Other than things like that. No, multiple methods are fine. Just give it a name that makes clear what methods belong in the class and what ones don't.

Uncle Bob's SRP is more about Conway's Law than Curly's Law. Uncle Bob advocates applying Curly's Law (do one thing) to functions not classes. SRP cautions against mixing reasons to change together. Conway's Law says the system will follow how an organization's information flows. That leads to following SRP because you don't care about what you never hear about.

"A module should be responsible to one, and only one, actor"

Robert C Martin - Clean Architecture

People keep wanting SRP to be about every reason to limit scope. There are more reasons to limit scope than SRP. I further limit scope by insisting the class be an abstraction that can take a name that ensures looking inside won't surprise you.

You can apply Curly's Law to classes. You're outside what Uncle Bob talks about but you can do it. Where you go wrong is when you start to think that means one function. That's like thinking a family should only have one child. Having more than one child doesn't stop it from being a family.

If you apply Curly's law to a class, everything in the class should be about a single unifying idea. That idea can be broad. The idea might be persistence. If some logging utility functions are in there, then they are clearly out of place. Doesn't matter if Mr X is the only one who cares about this code.

The classic principle to apply here is called Separation of Concerns. If you separate all your concerns it could be argued that what's left in any one place is one concern. That's what we called this idea before the 1991 movie City Slickers introduced us to the character Curly.

This is fine. It's just that what Uncle Bob calls a responsibility isn't a concern. A responsibility to him isn't something you focus on. It's something that can force you to change. You can focus on one concern and still create code that is responsible to different groups of people with different agendas.

Maybe you don't care about that. Fine. Thinking that holding to "do one thing" will solve all of your design woes shows a lack of imagination of what "one thing" can end up being. Another reason to limit scope is organization. You can nest many "one thing"s inside other "one thing"s until you have a junk drawer full of everything. I've talked about that before

Of course the classic OOP reason to limit scope is that the class has private fields in it and rather then use getters to share that data around, we put every method that needs that data in the class where they can use the data in private. Many find this too restrictive to use as a scope limiter because not every method that belongs together uses exactly the same fields. I like to ensure that whatever idea that brought the data together be the same idea that brought the methods together.

The functional way to look at this is that a.f(x) and a.g(x) are simply fa(x) and ga(x). Not two functions but a continuum of pairs of functions that vary together. The a doesn't even have to have data in it. It could simply be how you know which f and g implementation you're going to use. Functions that change together belong together. That's good old polymorphism.

SRP is just one of many reasons to limit scope. It's a good one. But not the only one.

Related Topic