Overview
The Interface Segregation Principle (ISP) says clients should not be forced to depend on methods they do not use. Instead of one large interface, define several small, role-specific interfaces. A class can implement many of them; each client depends only on the role it needs.
Fat interfaces cause implementers to write empty or throwing methods, and cause clients to be recompiled or retested when unrelated methods change. ISP keeps contracts cohesive, makes fakes in tests tiny, and pairs naturally with LSP.
Most people use five buttons. A simple remote for the TV and a separate one for the sound bar are easier to use, and replacing one does not affect the other.
When to use it
- Implementations leave methods empty or throw UnsupportedOperationException.
- Different clients use different subsets of an interface.
- Test fakes need to implement many irrelevant methods.
Where it shows up in interviews
Recognize it when: Machine with print, scan, fax, staple.
- Design a multifunction printer
- Design a Worker interface for humans and robots
Recognize it when: read-only clients vs writers.
- Design a repository with readers and writers
- Design an admin vs user API
Where it is used in real software
Readable, Closeable, Flushable, and AutoCloseable are tiny role interfaces combined as needed.
io.Reader and io.Writer are one-method interfaces; io.ReadWriter composes them.
Separating command and query interfaces is ISP at the service level.
Key terms
- Fat interface
- Interface with many unrelated methods.
- Role interface
- Small interface representing one client's needs.
- Interface composition
- Combining small interfaces into larger ones where needed.
How it works, step by step
- 1List the clients
Who calls this interface?
- 2Group methods by client usage
Which methods does each client call?
- 3Extract role interfaces
Printer, Scanner, Fax.
- 4Implement the relevant roles
A basic printer implements only Printer.
- 5Clients depend on their role
Not on the full implementation.
Splitting a Machine interface
interface Machine { print(); scan(); fax(); }
| Device | With fat Machine | With role interfaces |
|---|---|---|
| Basic printer | scan() and fax() throw | implements Printer |
| Scanner | print() and fax() throw | implements Scanner |
| All-in-one | implements everything | implements Printer, Scanner, Fax |
| Print-queue client | depends on scan and fax too | depends only on Printer |
NOWDevice: Basic printer | With fat Machine: scan() and fax() throw | With role interfaces: implements Printer
No more throwing stubs, and each client sees only what it needs.
Implementation
interface Printer { print(doc: string): void }interface Scanner { scan(): string }interface Fax { fax(doc: string, number: string): void } class BasicPrinter implements Printer { print(doc: string) { console.log("printing", doc); }} class OfficeMachine implements Printer, Scanner, Fax { print(doc: string) { console.log("printing", doc); } scan() { return "scanned-doc"; } fax(doc: string, number: string) { console.log("faxing", doc, "to", number); }} // Client depends only on the role it usesclass PrintQueue { constructor(private printer: Printer) {} flush(docs: string[]) { docs.forEach((d) => this.printer.print(d)); }} new PrintQueue(new BasicPrinter()).flush(["a.pdf"]);new PrintQueue(new OfficeMachine()).flush(["b.pdf"]);Complexity and performance
One per role.
Implement one role.
Trade-offs
Too many one-method interfaces fragment the design; group methods that are always used together.
Many small interfaces require good naming and documentation.
Variants and related techniques
interface ReadWriter extends Reader, Writer.
Wrap a large legacy API with narrow interfaces.
Common mistakes
- Splitting by implementation rather than client needs.
Fix: Design interfaces from the caller's perspective.
- Header interfaces mirroring every public method of a class.
Fix: Expose only what clients need.
Interview questions
How does ISP relate to LSP?
Fat interfaces force implementers to stub methods they cannot support, which breaks substitutability. Segregating interfaces lets each type implement only what it can honor.
Give an example of ISP in a real system.
Splitting a repository into reader and writer interfaces so reporting code gets read-only access, or Go's io.Reader and io.Writer used independently.
Practice problems
| Problem | Difficulty | What it trains |
|---|---|---|
| Split a Worker interface for humans and robots | Easy | Roles. |
| Design interfaces for a smart home device hub | Medium | Capabilities. |