In the following video, the author takes an existing class and assigns the Single Responsibility Principle to it. He takes a Print Class that has the job of Accessing Data, Formatting, and Printing the report. He breaks up each method to its own class, so he creates a DataAccess class to handle data access, he creates a ReportFormatter class to handle the formatting of the Report, and he creates a ReportPrinter class to handle the printing of the Report. The original Report class is then left with one method, Print() which calls the ReportPrinter's class method Print. DataAccess and ReportFormatter appear to have responsibility, but ReportPrinter relies on DataAcess and ReportFormatter, so doesn't this break the SRP or am I misunderstanding it?
问题:
回答1:
The Single Responsibility Principle indicates that a given class should have a single responsibility (or 'reason to change'). It does not, in and of itself, indicate how that responsibility is to be satisfied. Doing so can, and often does, require the cooperation of multiple other classes as collaborators.
回答2:
Without watching the video, it sounds like a reasonable design. SRP is not broken, as methods dealing with data access do not appear in the ReportPrinter class, only the concept that "I can call something to get the data I want."
You could push it a bit further, and have a coordinator class responsible only for coordinating the activities of the data access class, the formatter class, and the printer class. You could also arrange the objects in different ways, like having the coordinator sends data to the formatter, which sends it to the printer, and the coordinator doesn't (directly) know about the printer.
Something has to know about coordinating the efforts of the narrowly-focused objects. That becomes their responsibility. It's okay to know about the idea or concept of what the other objects will do, so long as you don't know or care how they do it. Thinking of interfaces as "seams of responsibility" is a good start.
It can also be helpful if you think of objects as passing data to each other, rather than "doing" things. So the ReportFormatter returns (or forwards) a new object representing a formatted report, rather than (conceptually) performing objects on an existing report.
回答3:
SRP doesn't address dependencies. Breaking the class up into the single-responsibility classes will facilitate breaking those dependencies later. SRP addresses one of the two principles oftem mentioned together: Cohesion and Coupling. SRP is about high cohesion, and the dependencies can be indicative of high coupling. Good designs have high cohesion and low coupling. Sometimes these two principles can be at odds.
回答4:
No. It does not break SRP.
Assume that
DataAccess implements IDataAccess
ReportFormatter implements IReportFormatter
ReportPrinter implements IReportPrinter
Event though ReportPrinter relies on DataAccess and ReportFormatter
, any change in contract of IDataAccess or IReportFormatter
should be implemented by DataAccess and ReportFormatter
respectively. ReportPrinter
does not worry about the responsibility changes in those classes.
You can have Composition
or implement Mediator pattern to provide loose coupling between these three classes and get job done. Keep coupling
part away from responsibility
.