Interface Segregation Principle (ISP)
Clients should not be forced to depend upon interfaces that they do not use.
Intent & Objective
Prefer many small, focused, client-specific interfaces over one large, generalized, "fat" interface. Classes implementing an interface should never be forced to throw dummy or empty implementations for methods they do not need.
"A TV viewer wants only Power, Volume, and Channel buttons, not an 80-button remote combining microwave and dishwasher controls."
The Problem
Fat interfaces force implementers to write hollow stub methods like `throw new UnsupportedOperationException()`. When one method in the fat interface changes, all implementers must recompile and test, even if they never invoked that method.
The Solution
Break down large interfaces into small, cohesive, role-based interfaces (e.g. `Printable`, `Scannable`, `Faxable` instead of `MultiFunctionDevice`).
Key Participants & Architectural Roles
Code Samples (Traditional OOP vs Functional Programming)
Available in C++, Python, and JavaParadigm Contrast: Traditional OOP vs Functional / Data-Oriented
In OOP, ISP is solved using multiple inheritance of interfaces (e.g. implementing `Printer` and `Scanner` separately). In Functional Programming, ISP is inherently satisfied because functions take only the exact callback or value they need (e.g. passing a single `Consumer` or `Function`) instead of receiving a bloated interface.
Advantages
- β Eliminates dead code and dummy exception-throwing stubs
- β Enhances decoupling and makes components much easier to mock in tests
- β Encourages composable, modular designs
Trade-offs
- β Can increase the total number of interface definitions
When to Apply
- β When an interface has methods that some implementers leave blank or throw `NotImplementedException`
- β When different clients of an interface consume completely disjoint subsets of its methods
When to Avoid
- ! When every method in the interface is logically inseparable and needed by all consumers