Skip to main content

Interface Segregation: Small, Role-Based Interfaces

What This Concept Is

The Interface Segregation Principle (ISP) says:

No client should be forced to depend on methods it does not use.

Instead of one large interface that every collaborator implements in full, split responsibilities into several smaller, role-based interfaces. Each client depends only on the role it actually plays.

ISP is coupling discipline at the interface level. Broad interfaces advertise a broad contract; every caller now knows about methods it does not use, and the interface's authors cannot change any method without ripple.

Why It Matters Here

Wide interfaces are a common symptom of facade-worship: one Library, Service, or Manager class claims to do everything for everyone. Internal clients end up depending on the facade's entire surface area, so changes intended for external clients ripple into internal ones.

ISP is also the cleanest way to make test doubles sane. Small, role-based interfaces make it obvious which method the test cares about.

Concrete Example

ISP violation -- one god-interface:

interface Printer {
void print(Document d);
void fax(Document d);
void scan(Document d);
void staple(Document d);
}

class OldPrinter implements Printer {
public void print(Document d) { /* ok */ }
public void fax(Document d) { throw new UnsupportedOperationException(); }
public void scan(Document d) { throw new UnsupportedOperationException(); }
public void staple(Document d){ throw new UnsupportedOperationException(); }
}

OldPrinter is forced to depend on -- and lie about -- operations it does not support. Any caller that gets a Printer reference has no way to know which subset is real.

ISP-respecting version -- separate roles:

interface Printable { void print(Document d); }
interface Faxable { void fax(Document d); }
interface Scannable { void scan(Document d); }
interface Staplable { void staple(Document d); }

class OldPrinter implements Printable { public void print(Document d) { /* ok */ } }
class Multifunction implements Printable, Faxable, Scannable, Staplable { /* ... */ }

Callers now depend on exactly the roles they need, and the old printer does not lie.

Common Confusion / Misconception

"ISP means every interface should have one method." Not always. An interface should be as wide as one cohesive role. Iterator has hasNext() and next() together because they are the same role. Splitting them would not help anyone.

A related confusion: "ISP means to split implementations." ISP is about client-facing interfaces. Implementations are free to be larger; clients should depend on the smaller role.

How To Use It

When designing or reviewing an interface:

  1. List the clients that will depend on it.
  2. For each client, mark which methods it actually calls.
  3. If the mark matrix has holes (clients that depend on only a subset), split the interface along those holes.
  4. Name the new interfaces after roles (-able, -or, -er) rather than after modules (XyzService).

Check Yourself

  1. Why is "just throw UnsupportedOperationException" a bad answer to an interface that is too wide?
  2. Why can one implementation class implement many small interfaces without violating ISP?
  3. Why is ISP easier to apply once clients are identifiable?

Mini Drill or Application

Find an interface or abstract class with at least five methods in a codebase you know. Do all four:

  1. List every caller and which methods they use.
  2. Draw the usage matrix (clients × methods).
  3. Identify clusters of methods used by the same clients.
  4. Propose a split and give the new interfaces role-based names.

Read This Only If Stuck