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
}