Interface Segregation Principle (ISP)
Split fat interfaces into focused ones β no class should be forced to implement methods it will never use.
Intent & Description
π― Intent
Large interfaces force implementing classes to provide stub or error implementations for methods that don’t apply to them β dead code, broken contracts, and unnecessary coupling.
π Context
A Robot class extends Worker and is forced to implement eat() and sleep() β methods that make no sense for a robot. Every change to those methods ripples to Robot even though it’s irrelevant. The interface has leaked its assumptions about humans into an unrelated class.
π‘ Solution
Break the large interface into smaller, focused ones. A robot implements only Workable. A human implements Workable, Eatable, and Sleepable. Each implementor depends only on the contract it actually honors.
Real-world Use Case
π TL;DR
Split fat interfaces. Clients should only depend on methods they actually call β unused method coupling is invisible technical debt.
Advantages
- Small interfaces are easy to understand, implement, and document
- Clients depend only on what they actually use β no phantom coupling
- Interface changes ripple only to the classes that are genuinely affected
Disadvantages
- More interfaces to name, manage, and discover
- Over-segregation produces so many micro-interfaces it becomes its own maintenance burden
- Requires discipline to resist collapsing them back into one big contract
// Before: Large interface
class Worker {
work() {
console.log('Working');
}
eat() {
console.log('Eating lunch');
}
sleep() {
console.log('Sleeping');
}
}
class Robot extends Worker {
eat() {
throw new Error('Robots dont eat'); // Forced to implement
}
sleep() {
throw new Error('Robots dont sleep'); // Forced to implement
}
}
// After: ISP applied
class Workable {
work() {
throw new Error('Must implement work');
}
}
class Eatable {
eat() {
throw new Error('Must implement eat');
}
}
class Sleepable {
sleep() {
throw new Error('Must implement sleep');
}
}
class Human implements Workable, Eatable, Sleepable {
work() { console.log('Working'); }
eat() { console.log('Eating'); }
sleep() { console.log('Sleeping'); }
}
class Robot implements Workable {
work() { console.log('Working'); }
// No need to implement eat or sleep
}