In SOLID, what is the distinction between SRP and ISP? (Single Responsibility Principle and Interface Segregation Principle)
D

6

82

How does the SOLID "Interface Segregation Principle" differ from "Single Responsibility Principle"?

The Wikipedia entry for SOLID says that

ISP splits interfaces which are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them

However, to me that sounds like just applying the SRP to interfaces as well as classes. After all, if an interface is only responsible for just one conceptual thing, than you wouldn't be able to break it down further.

Am I missing something, or is ISP sort of redundant with SRP? If not, then what does ISP imply that SRP does not?

Disclaim answered 17/1, 2013 at 21:20 Comment(4)
Possible duplicate for #8099510Gromyko
I suppose technically, but this question is IMHO better written and the answers more fleshed out.Disclaim
They are the same thing, but it's not the same saying "SOLID principles" than "SOLD principles". We needed another char to create a bombastic word.Keeper
@Cequiel, the acronym was created years after the five principles were published, and the acronym was created by a different person (Michael Feathers) than the principles (Bob Martin).Todtoday
H
51

SRP tells us that you should only have a single responsibility in a module.

ISP tells us that you should not be forced to be confronted with more than you actually need. If you want to use a print() method from interface I, you shouldn't have to instantiate a SwimmingPool or a DriveThru class for that.

More concretely, and going straight to the point, they are different views on the same idea -- SRP is more focused on the designer-side point-of-view, while ISP is more focused on the client-side point-of-view. So you're basically right.

It all came from

The ISP was first used and formulated by Robert C. Martin when doing some consulting for Xerox. Xerox had created a new printer system that could perform a variety of tasks like stapling a set of printed papers and faxing. The software for this system was created from the ground up and performed its tasks successfully. As the software grew, making modification became more and more difficult so that even the smallest change would take a redeployment cycle to an hour. This was making it near impossible to continue development. The design problem was that one main Job class was used by almost all of the tasks. Anytime a print job or a stapling job had to be done, a call was made to some method in the Job class. This resulted in a huge or 'fat' class with multitudes of methods specific to a variety of different clients. Because of this design, a staple job would know about all the methods of the print job, even though there was no use for them.

so

The solution suggested by Martin is what is called the Interface Segregation Principle today. Applied to the Xerox software, a layer of interfaces between the Job class and all of its clients was added using the Dependency Inversion Principle. Instead of having one large Job class, a Staple Job interface or a Print Job interface was created that would be used by the Staple or Print classes, respectively, calling methods of the Job class. Therefore, one interface was created for each job, which were all implemented by the Job class.

@ http://en.wikipedia.org/wiki/Interface_segregation_principle#Origin

Hilmahilt answered 17/1, 2013 at 21:24 Comment(5)
Hmm, the only distinction I see from your post is "If you want to use a print() method from interface I, you shouldn't have to instantiate a SwimmingPool or a DriveThru class for that." which frankly sounds a lot like "You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.". Are you saying that the banana comment is a paraphrase of ISP?Disclaim
You often see badly designed code in which for making use of some feature, you have to first turn on the logging, then turn on A, B and C services, while all you wanted to do was to calculate the area of an ellipsis which is something you'd expect to not require all that ado.Hilmahilt
Can you give me source to this article?Waldon
Rightly or wrongly, I downvoted as I think SWeko's answer is a lot more powerful and easier to understand.Cismontane
Thats clearly a violation of SRP in the example, so to me distinction isn't clear.Farouche
H
24

SRP is concerned with what a module does, and how it is done, disallowing any mix of abstraction levels. Basically, as long as a component can be extensively defined with a single sentence, it will not break SRP.

On the other hand ISP is concerned with how a module should be consumed, whether it makes sense to consume just part of the module, while ignoring some aspect.

As an example of a code that keeps the spirit or SRP, but can break ISP is the Facade pattern. It has a single responsibility, "providing simplified access to a larger subsystem", but if the underlying subsystem needs to expose wildly different thinks, it does break ISP.

That said, usually when a piece of code breaks a SOLID principle, it often breaks the whole lot. Concrete examples that break a specific principle, while preserving the rest are rare in the wild.

Hindward answered 17/1, 2013 at 21:39 Comment(0)
T
20

Robert Martin tweeted the following on May 16, 2018.

ISP can be seen as similar to SRP for interfaces; but it is more than that. ISP generalizes into: “Don’t depend on more than you need.” SRP generalizes to “Gather together things that change for the same reasons and at the same times.”

Imagine a stack class with both push and pop. Imagine a client that only pushes. If that client depends upon the stack interface, it depends upon pop, which it does not need. SRP would not separate push from pop; ISP would.

Todtoday answered 9/3, 2019 at 1:6 Comment(1)
On the other hand, Mark Seemann thinks the SRP and ISP are close enough to be redundant.Todtoday
B
5

SRP and ISP ultimately boils down to the same things. Implementing, either of them, needs a split of classes or interfaces.

However there are differences on other fronts.

  1. Violation of SRP can have a far reaching effects on the entire design structure, giving rise to poor maintainability, reuse and of course low cohesion and coupling.
  2. SRP has an impact on both the behavioral and structural components of an object structure.
  3. Re designing on SRP violation needs a much deeper analysis, require looking at the different components of design in a holistic way.

Violation of ISP is mostly about poor readability ( and to some degree, low cohesion ). But the impact on maintenance and code re-use is far less sinister than SRP.

Moreover, refactoring code to ISP conformation, seems to be just a structural change.

See also my blog for SRP and ISP

Baldachin answered 18/12, 2013 at 10:50 Comment(9)
The point I've come to take is that SRP is one responsibility in the domain, whereas ISP is a single behaviour. So in a library having one class for Books and one for Movies is a SRP, but then the getDueDate() and getMexRenewal() being their own interface (eg Rentable) from getId() (eg Identifiable) is ISP, even if all Rentable classes will be Identifiable as well. It's almost as it if the definition of "atomic" or "separate" is different for interfaces than it is for classes.Disclaim
There is no formal definition for 'atomic' or 'separate'. In that respect the design considerations for building a class are the same as that of interface.Baldachin
Will it be wrong to say that methods of interface define a responsibility for the implementing class ? It must be, otherwise there are some overridden methods of interface having a 'NIL' implementation in the implemented class. To put in your words, Interface methods ( put together ) define an 'atomic' behaviour of a type. Classes 'atomic' behaviour, or the so called 'responsibility' is an aggregate of many such behaviours. ( And ofcourse, for a non final class, all the public methods must be substitutable with different implementations )Baldachin
In that respect the design considerations for building a class are the same as that of interface. I disagree, I find in clean code the scope of responsibilities of an interface much narrower than that of an entire class. You will find an interface that defines a single getId() method but you'll never find a class with just a getId() method. Interfaces usually have narrower scopes.Disclaim
Yes, definitely. Interfaces just define a unit behaviour. Multiple unit behaviours may be one responsibility for a class.Baldachin
That comment is probably the best answer for why and how SRP and ISP differ.Disclaim
Yes, but well there is another important point of concerns. How to define a responsibility of a class ... Attempts to find a objective answer brings forth some subtle differencesBaldachin
Is there a blog post that defines "unit behaviour" and "responsibility" more precisely?Disclaim
Not sure if this can be of any use : design-principle-pattern.blogspot.in/2013/12/…Baldachin
O
1

From the point of my understanding, both principles are complementary, i.e. they need to be combined.

The ultimate consequence of violating ISP is becoming fragile, "shotgun surgury" or a "butterfly effect". A lot of code can break or require code updates because they depend onto some interface or objects which provide more than they needed. Changes become excessive.

The consequence of violating SRP is mainly decreased readability and maintentance. The lack of clear code structure may require people to search across the code base (a single responsibility is too distributed) or within a single large unit (multiple responsibilities scrammed together) to make a coherent change. In General, it is increased overhead to fully understand the concern (purpose) of some code snippet. Changes are prevented.

In that way, both principles act like a lower and upper bound for sane change management.

Examples for satisfying RSP without ISP – as provided by the other answers – express that there can be code which truly would belong together (like the stack example quote from Robert C. Martin). But it may do too much, is overengineered, etc. Maybe in very small examples, the effect is not visible, but if it grows large, it may be more comfortable to have a depending class still compile correctly after some unrelated part in the (indirect) dependency was changed. Rather than not compile anymore because unrelated things were changed.

Ozmo answered 4/5, 2022 at 21:31 Comment(0)
O
1

Key Differences:

Scope:

SRP: It focuses on the responsibilities of a class, ensuring that a class has only one reason to change.

ISP: It focuses on the design of interfaces, ensuring that they are not bloated with unnecessary methods, and clients don't depend on methods they don't need. Level of Abstraction:

SRP: It applies at the class level, addressing the responsibilities within a single class.

ISP: It applies at the interface level, addressing how interfaces are designed and used by classes. Concerns:

SRP: It is concerned with class cohesion and maintainability.

ISP: It is concerned with minimizing dependencies and promoting flexibility.

Ore answered 30/10, 2023 at 18:30 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Fennelflower

© 2022 - 2024 — McMap. All rights reserved.