ISP
Why force a class to implement methods it doesn't need? Master the Interface Segregation Principle to build lean and focused contracts.
The Interface Segregation Principle (ISP) states that no client should be forced to depend on methods it does not use. In simpler terms: Leaner is Better.
The Essentials
The "Lean Contract" guide:
- Avoid "Fat" Interfaces: Don't shove every possible behavior into a single giant interface.
- Specific Needs: A class should only implement the methods it actually needs to perform its job.
- Decomposition: Break large interfaces into smaller, more focused ones.
- Decoupling: By having smaller interfaces, changes to one behavior won't force unrelated classes to re-compile.
The Menu Analogy
Imagine you are at a restaurant that only has one "Mega-Meal" on the menu.
- The Problem: The meal includes a burger, fries, a salad, a soda, and a cake.
- The Client: You only want the burger.
- The Forced Dependency: You are forced to "pay" for and "handle" the salad and cake even though you have zero interest in them.
"Fat" Interfaces are like that Mega-Meal. If you have a Worker interface with work() and eat(), and you have a Robot class, you are forcing the robot to implement an eat() method that it doesn't need.
ISP in Action: The Interface Problem
The Worker interface forces all clients to implement eat(), even if they are Robots.
work();
eat();
}
class Robot implements Worker {
eat() { throw Error(); }
}
This "pollutes" the class with methods it doesn't need. It's a sign of a bad abstraction.
We split the giant interface into smaller, focused ones. Clients only pick what they actually use.
interface Eatable { eat(); }
class Human implements Workable, Eatable { .. }
class Robot implements Workable { .. }
The Robot is no longer forced to "know" about eating. The code is lean and highly decoupled.
Code Implementation: Segregating Responsibilities
Here is how you refactor a "Fat" interface into specialized "Lean" ones:
// Focused interfaces (Lean Contracts)
interface Workable {
work(): void;
}
interface Eatable {
eat(): void;
}
interface Sleepable {
sleep(): void;
}
// A Human needs everything
class Human implements Workable, Eatable, Sleepable {
work() { console.log("Human working..."); }
eat() { console.log("Human eating lunch..."); }
sleep() { console.log("Human sleeping..."); }
}
// A Robot ONLY needs to work
class Robot implements Workable {
work() { console.log("Robot processing data..."); }
}
// A smart machine might work and sleep (low power mode)
class SmartMachine implements Workable, Sleepable {
work() { console.log("Machine running..."); }
sleep() { console.log("Machine in low-power mode..."); }
}Why It Matters: Focused Code
- Less Pollution: Your classes stay clean. You don't have empty methods or "NotImplemented" errors cluttering your code.
- Modular Stability: If you change the
Eatableinterface, theRobotclass isn't affected at all.
By following ISP, you create a system of "Lean and Focused" contracts that make your code more flexible and much easier to maintain.
Next, we'll reach the final pillar: the Dependency Inversion Principle, and see the magic of decoupling.
Practice what you just read.