Writing Cleaner Code with the Interface Segregation Principle (ISP)
Have you ever had to implement a method in Java that your class doesn’t even need?
That’s a classic code smell—and the Interface Segregation Principle (ISP) from SOLID helps us avoid it.
What is ISP?
❝ Clients should not be forced to depend on methods they do not use. ❞
In simple terms: "Don’t force classes to implement methods they don’t need."
Let’s break this down with an example:
👎 Before ISP:
Imagine you’re designing a UI library with different widgets like labels, buttons, and panels. To keep things uniform, you define a common Widget interface for them all…
public interface Widget {
void render();
void onClick();
void onResize();
}
Now let’s implement this Widget interface for different UI components:
But here’s the catch—all of them are forced to implement all three methods, even if they don’t need them…
public class LabelWidget implements Widget {
@Override
public void render() {
System.out.println("Rendering label");
}
@Override
public void onClick() {
// Label doesn't need click functionality
// Empty implementation violates ISP
}
@Override
public void onResize() {
// Label doesn't need resize functionality
// Empty implementation violates ISP
}
}
public class ButtonWidget implements Widget {
@Override
public void render() {
System.out.println("Rendering button");
}
@Override
public void onClick() {
System.out.println("Button clicked");
}
@Override
public void onResize() {
// Button doesn't really need resize functionality
// Empty implementation violates ISP
}
}
public class PanelWidget implements Widget {
@Override
public void render() {
System.out.println("Rendering panel");
}
@Override
public void onClick() {
// Panel doesn't really need click functionality
// Empty implementation violates ISP
}
@Override
public void onResize() {
System.out.println("Panel resized");
}
}
👍 After applying ISP:
Each interface now represents a single capability:
public interface Renderable {
void render();
}
public interface Clickable {
void onClick();
}
public interface Resizable {
void onResize();
}
Now let’s see how each widget looks with the new, focused interfaces:
Each class is now clean and specific to its behavior.
public class LabelWidget implements Renderable {
@Override
public void render() {
System.out.println("Rendering label");
}
}
public class ButtonWidget implements Renderable, Clickable {
@Override
public void render() {
System.out.println("Rendering button");
}
@Override
public void onClick() {
System.out.println("Button clicked");
}
}
public class PanelWidget implements Renderable, Resizable {
@Override
public void render() {
System.out.println("Rendering panel");
}
@Override
public void onResize() {
System.out.println("Panel resized");
}
}
Benefits of ISP:
By respecting ISP, we avoid forcing unnecessary responsibilities onto our classes—leading to robust and maintainable systems.
Have you ever worked with bloated interfaces that didn’t respect ISP? How did you refactor them?
#Java #CleanCode #SOLIDPrinciples #InterfaceSegregation #SoftwareDesign #OOP #BackendDevelopment #CodeRefactoring #DevLife
💡 Great insight
Fully agree