Is high cohesion a synonym for the Single Responsibility Principle? If not, how are they different?
问题:
回答1:
The are not the same thing.
You can have a highly cohesive class that does not have just a single responsibility.
回答2:
You asked: If not, how are they different?
Single Responsibility Principle
Throw out whatever you think you guess this principle means.
Robert C. Martin officially defines this principle as:
A class should only have one reason to change
Most people defining SRP are incorrect. SRP is typically mis-explained as:
"The Employee
class shouldn't UpdateDemographics()
and SendMessage()
, that counts as two responsibilities... put SendMessage()
into a Message class!!"
^^ Wrong
vv Right
Robert C. Martin says
"A responsibility is not 'something the code does'". (NDC 2012)
Robert C. Martin defines SRP as:
"Any module should be responsible to only one person-[role]." (NDC 2012)
When a Stakeholder asks for a change to the data-sorting in the View, management shouldn't freak out and worry that the algorithms will break. Because The module that handles Sorting on the View is responsible only to the stakeholder, and The module that handles the total-calculating algorithm is responsible only to the business analyst. So when the Business Analyst asks to make a change to the algorithm, we shouldn't fear that the View will change.
Therefore, A module (singular) should only ever change for one reason: The Single Person-Role for whom this module serves has requested a change.
With that as your new foundation for the definition of SRP, you can now apply what you thought SRP was previously, and make the definition a bit more granular. Nobody is saying to put all of your front-end code into one module and all of your back-end code into one module.
High Cohesion
Imagine that you have a method decimal CalculatePayFor(Employee)
and another method void Pay(Employee)
Do these belong together? There could be a service that performs calculations of all sorts, and there could be a service that does nothing more than wrap the Human-Resources Payment SOAP. Perhaps Pay(Employee)
calls into CalculatePayFor(Employee)
, but just because they have the word Pay
in them doesn't mean they belong together!
How do I create cohesion? - You don't. Cohesion is something you observe. What you do is Don't tear things apart that belong together.
It is possible to create a class for every public method you want. Each class now has one public method and everything is a well-defined mess. You have classes named PayrollClass1
and PayrollClass2
because one does calculations one way, and the other does calculations two way.
Some languages even benefit from a complete lack of classes, and methods run free. There is no grouping of methods, methods are just methods that you can call whenever. They're all pretty much static.
However, You Can Observe that CalculatePayFor(Employee)
and Pay(Employee)
are actually VERY Highly bound. They are like a dang married couple, and they look great together. When methods clearly belong together, you don't want to tear them apart. Observe their natural state and set up a wildlife preserve. This is Maintaining High Cohesion. You don't create it, you observe it.
What this really helps with is Proper Code Duplication. For example, PayrollService.CalculatePayFor(Employee)
has the same exact code as ReportService.CalculatePayFor(Employee)
. Is this bad? Of course not. If Senior Management asks to make a change in the calculation for employee pay for the sake of reporting, that's a different responsibility than if H.R. tells you to make a change for the calculation for tax purposes for the actual payment method.
"Wait, did he just mix up SRP and Cohesion?" No, but I'm glad you recognized the mix-up. What if the ReportService reached into the PayrollService' class and used its method? Then when it changes for legitimate payment purposes, the reports all change... but management didn't want that!!! So since Cohesion forces methods to stay to their own classes, and SRP forces modules to keep to themselves within an application, the ReportService is forced to Copy/Paste the method from the PayrollService class. Now they can change independent of each other.
"But what if that isn't what you want?" Well, there are a lot of places in code where duplication is ruled out. But it is most common for algorithms to stick to themselves, and change independently of the dependencies. Even if that means duplication. It just depends what is needed. But Separation of Concerns, Single Responsibility, Cohesion, and DRY (Don't Repeat Yourself) are all separate ideas.
Side-Note: DRY Doesn't mean there is never duplication. As I mentioned: Many times you can have duplicate code because business rules are similar amongst different concerns, and have different reasons to change.
回答3:
It's not a synonym. SRP (Single Responsibility Principle) is when you ensure yours classes will have only one responsibility. For sure this increases your classes cohesion.
But you can have high cohesion without following SRP to the letter.
Here is a good source on that.
回答4:
In Robert Martin's own words,
If you think about [SRP] you’ll realize that this is just another way to define cohesion and coupling. We want to increase the cohesion between things that change for the same reasons, and we want to decrease the coupling between those things that change for different reasons.
See also: Difference between Single Responsibility Principle and Separation of Concerns.