Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Interface Segregation Principle
LLD

Interface Segregation Principle

Understand why clients should depend on focused interfaces rather than large interfaces containing unused methods.

Interface Segregation Principle (ISP)

The Problem It Solves

One interface to rule the domain:

interface Worker {
    void work(); void eat(); void sleep();
}
class Robot implements Worker {
    public void work() { assemble(); }
    public void eat()  { throw new UnsupportedOperationException(); } // ← lie
    public void sleep(){ throw new UnsupportedOperationException(); } // ← lie
}

Every Worker-typed client drags dependencies on eating and sleeping it never uses. Every implementer that can’t eat must fake it. The fat interface forces lies into the codebase, and lies surface as runtime exceptions. ISP (Robert C. Martin): clients should not be forced to depend on methods they do not use — split interfaces by client role.

The Split

 FAT INTERFACE                    SEGREGATED BY ROLE

 ┌─────────────────┐              ┌──────────────┐  ┌──────────────┐
 │     Worker      │              │   Workable   │  │   Feedable   │
 │ work() eat()    │              │ + work()     │  │ + eat()      │
 │ sleep()         │              └──────△───────┘  └──────△───────┘
 └───△────△────△───┘                     │                │
     │    │    │                  ┌──────┴────┐     ┌─────┴─────┐
  Robot Human Manager             │   Robot   │     │   Human   │
  (fakes 2)  (fine)(never sleeps?)│ implements│     │implements │
                                 │ Workable  │     │  both     │
                                 └───────────┘     └───────────┘

Robot implements only what it truthfully does. Clients depending on Workable never see eat() at all — their dependency shrank with the interface.

Mechanics

interface Workable { void work(); }
interface Feedable { void eat(); }

class Robot implements Workable {
    public void work() { assemble(); }
}
class Human implements Workable, Feedable {
    public void work() { think(); }
    public void eat()  { lunch(); }
}

Multiple small interfaces compose; Java’s unlimited implements makes segregation free of the single-inheritance constraint.

Where Fat Interfaces Hide

  • Service interfaces grown by accretion: UserService with 25 methods — every mock in every test implements 25 stubs.
  • Framework callbacks: listeners demanding ten no-op overrides → fixed by adapter defaults or split listener types (MouseListener vs MouseMotionListener in AWT).
  • Repository interfaces: findByName, countByStatus, exportCsv used by different callers who each need one-tenth.

Trade-offs

Fat interfaceSegregated
Interface countFewMany small ones
Implementer honestyForced stubsOnly real capabilities
Client dependency surfaceEverythingExactly what’s used
Evolution riskAny change touches allChange isolated per role
Over-segregation costChurn re-bucketing tiny interfaces

Detection Signals

  • Empty/throwing override bodies.
  • Interfaces named after things (Manager) rather than capabilities (Workable).
  • Test mocks with dozens of unused stubbed methods.
  • Documentation comments saying “not applicable for X implementations.”

Interview Framing

  • The robot example is the canonical opener; recognizing it instantly is expected.
  • Senior nuance: ISP pairs with OCP — segregated interfaces are also the stable extension seams; fat interfaces freeze wrongly because every addition touches all implementers.

The Craft Behind ISP

Segregation says split; lean design decides how small, named after what, and how it evolves. A lean interface contains exactly the methods one client role needs, named for the capability, with a documented contract — and nothing else. Every extra method is a permanent tax on all implementers and all readers.

Role-Based Discovery

Interfaces are discovered from client needs, not provider capability:

 WRONG question                     RIGHT question
 "What can PaymentGateway do?"      "What does RefundService need?"
 → list 20 gateway methods          → refund(Money, PaymentRef) only
 → interface mirrors vendor SDK     → one-method role interface,
 → every client sees everything       vendor adapter maps to it

The right-hand process yields interfaces matching domain vocabulary instead of third-party API shapes — vendors become swappable details.

Minimality Audit

CheckQuestion
Per methodWhich concrete client calls this? Name it or cut it
Per parameterIs this data the client legitimately knows?
CohesionWould removing any method break the role’s story?
NamingDoes the name state capability (Workable) not implementation (WorkerManager)?
Return typesDoes any return leak internal types (entities, builders)?

Contract Documentation

A lean interface still needs its semantics written:

/**
 * Atomically reserves seats; hold expires after ttlMinutes if unconfirmed.
 * Thread-safe. Throws SeatsUnavailableException without side effects.
 */
interface SeatInventory {
    Hold reserve(ShowId show, List<SeatId> seats);
}

Atomicity, expiry, thread-safety, failure atomicity — clients code against these words. Undocumented interfaces force implementer-reading, defeating segregation’s decoupling purpose.

Default Methods as Evolution Tool

Interfaces must evolve without breaking implementers — Java 8’s answer:

interface SeatInventory {
    Hold reserve(ShowId show, List<SeatId> seats);

    /** @since 2.0 bulk variant; default delegates per-seat for old impls */
    default List<Hold> reserveAll(ShowId show, List<SeatId> seats) {
        return seats.stream().map(s -> reserve(show, List.of(s))).toList();
    }
}

Old implementations keep compiling via the default; performance-critical ones override. This is how Collection gained streams without breaking the ecosystem.

Trade-offs

PressureLean answer
”Just add it to the interface” (convenience)New narrow interface or default method — never accretion
Two roles share 80% of methodsShare the overlapping interface; keep role-specific ones separate
Vendor SDK shapes leaking inAdapter mapping vendor → domain role interfaces

Interview Framing

  • Reviewing a candidate-drawn interface and asking “who calls each of these?” is a standard senior probe — designing interfaces that survive it wins.
  • Citing Comparator vs Comparable as pre-built segregation (external strategy vs internal identity ordering) shows the pattern recognized in the wild.

My Private Notes

Notes are auto-saved locally to this device.