All Posts

Interface Segregation Principle: No Fat Interfaces

Clients shouldn't be forced to depend on methods they don't use. We explain the 'I' in SOLID with...

Abstract AlgorithmsAbstract Algorithms
ยทยท5 min read
Share
Share on X / Twitter
Share on LinkedIn
Copy link

TLDR: The Interface Segregation Principle (ISP) states that clients should not be forced to depend on methods they don't use. Split large "fat" interfaces into smaller, role-specific ones. A RoboticDuck should not be forced to implement fly() just because it's in a Bird interface.


๐Ÿ“– The Fat Remote Control Problem

Imagine a TV remote with 50 buttons. You only ever use 5: power, volume, channel up/down, and input select. ISP says: don't give every device the full remote. Give each device the buttons it actually needs.

In software, a fat interface forces every implementing class to provide methods it doesn't need, creating:

  • Stub implementations that throw UnsupportedOperationException.
  • Tight coupling โ€” changes to the fat interface force all implementers to update.
  • Fragile tests โ€” mocking 30 methods to test 2.

๐Ÿ” The Classic Violation: The Printer Interface

public interface Machine {
    void print(Document d);
    void scan(Document d);
    void fax(Document d);
    void copy(Document d);
    void staple(Document d);
}

public class SimplePrinter implements Machine {
    public void print(Document d) { /* works */ }
    public void scan(Document d)  { throw new UnsupportedOperationException(); }
    public void fax(Document d)   { throw new UnsupportedOperationException(); }
    public void copy(Document d)  { throw new UnsupportedOperationException(); }
    public void staple(Document d){ throw new UnsupportedOperationException(); }
}

SimplePrinter can only print โ€” but the Machine interface forces it to "implement" 4 other operations it can't do. Any code that calls simplePrinter.fax() fails at runtime rather than at compile time.


โš™๏ธ Applying ISP: Split by Role

// Segregated interfaces โ€” each is a single capability
public interface Printable  { void print(Document d); }
public interface Scannable  { void scan(Document d); }
public interface Faxable    { void fax(Document d); }
public interface Copyable   { void copy(Document d); }
public interface Stapleable { void staple(Document d); }

// Simple printer: only what it can do
public class SimplePrinter implements Printable {
    public void print(Document d) { /* full implementation */ }
}

// All-in-one office printer: combines all
public class OfficePrinter implements Printable, Scannable, Faxable, Copyable, Stapleable {
    public void print(Document d)  { /* ... */ }
    public void scan(Document d)   { /* ... */ }
    public void fax(Document d)    { /* ... */ }
    public void copy(Document d)   { /* ... */ }
    public void staple(Document d) { /* ... */ }
}
classDiagram
    class Printable { +print(d) }
    class Scannable { +scan(d) }
    class Faxable   { +fax(d) }

    SimplePrinter ..|> Printable
    OfficePrinter ..|> Printable
    OfficePrinter ..|> Scannable
    OfficePrinter ..|> Faxable

Now:

  • SimplePrinter compiles and works with zero stubs.
  • OfficePrinter implements everything it genuinely supports.
  • Code that only needs Printable accepts both โ€” no forced coupling.

๐Ÿง  Python Version: Protocol-Based ISP

Python uses structural subtyping via Protocol (PEP 544) โ€” no explicit implements required:

from typing import Protocol

class Printable(Protocol):
    def print(self, doc: str) -> None: ...

class Scannable(Protocol):
    def scan(self) -> str: ...

class SimplePrinter:
    def print(self, doc: str) -> None:
        print(f"Printing: {doc}")

def send_to_printer(device: Printable, doc: str) -> None:
    device.print(doc)

send_to_printer(SimplePrinter(), "Invoice.pdf")  # OK โ€” duck typing via Protocol

SimplePrinter never declared it implements Printable. The type checker confirms structural compatibility at analysis time without runtime overhead.


โš–๏ธ ISP vs Other SOLID Principles

ISP is closely related to:

PrincipleFocusRelationship to ISP
SRP (Single Responsibility)Classes have one reason to changeISP = SRP applied to interfaces
DIP (Dependency Inversion)Depend on abstractions, not concretionsISP keeps those abstractions narrow
OCP (Open/Closed)Extend without modifyingNarrow interfaces are easier to extend without breaking others

Rule of thumb: If you ask "when would a class mock or stub this method just to satisfy the interface?", that method doesn't belong in that interface.

When Fat Interfaces Are Acceptable

SituationVerdict
All implementations genuinely use all methodsFat interface is fine โ€” it's cohesive
Interface will never be implemented outside your teamAcceptable technical debt
Splitting creates so many tiny interfaces it hurts readabilityConsolidate to 2โ€“3 cohesive groups
Library API that external code depends onApply ISP strictly โ€” breaking changes are costly

๐Ÿ“Œ Summary

  • Fat interfaces force stub implementations and tight coupling โ€” avoid UnsupportedOperationException as a design smell.
  • Split by role: Each interface represents one capability. Classes implement only what they support.
  • Java uses explicit interface implementation; Python achieves the same with Protocol and duck typing.
  • ISP = SRP for interfaces: One reason to change, one capability per interface.
  • Apply strictly when the interface is part of a public API or library boundary.

๐Ÿ“ Practice Quiz

  1. A RemoteControl interface has methods turnOn(), changeChannel(), setTemperature(). A TVRemote class implements it but throws UnsupportedOperationException on setTemperature(). Which SOLID violation is this?

    • A) SRP โ€” the remote has too many responsibilities.
    • B) ISP โ€” TVRemote is forced to implement a method it doesn't support because the interface is too fat.
    • C) OCP โ€” the remote can't be extended.
      Answer: B
  2. After splitting Machine into Printable, Scannable, and Faxable, what does a SimplePrinter class implement?

    • A) All three interfaces with stubs for the others.
    • B) Only Printable โ€” the interfaces it genuinely supports.
    • C) None โ€” it uses reflection.
      Answer: B
  3. In Python, which feature enables ISP-style narrow interface enforcement without explicit implements declarations?

    • A) Abstract Base Classes (ABC) with @abstractmethod.
    • B) Protocol from the typing module โ€” structural subtyping checked by the type checker.
    • C) dataclass decorator.
      Answer: B

Abstract Algorithms

Written by

Abstract Algorithms

@abstractalgorithms