Interface Segregation Principle
Don’t force clients to depend on methods they don’t use.
Intent
Prefer many small interfaces over one fat interface. A print-only device should only know about printing.
Problem
Machine demands print, fax, and scan. An old printer can only print. It still must stub fax and raise on scan — a lie forced by the base type.
Solution
Split into Printer, Scanner, and Fax. Implement only what you need. A multi-function device composes the small roles.
Structure
| Piece | Role |
|---|---|
Machine / OldFashionedPrinter | Fat interface (violation) |
Printer / Scanner / Fax | Segregated interfaces |
*Impl classes | Focused implementations |
MultiFunctionDeviceImpl | Delegates to _printer, _scanner, _fax |
Compare code
Violation — fat Machine
python
class OldFashionedPrinter(Machine):
def print(self, document): ...
def fax(self, document): pass # forced
def scan(self, document):
raise NotImplementedError # forcedCompliant — small interfaces + compose
python
class PrinterImpl(Printer):
def print(self, document):
print(document)
class MultiFunctionDeviceImpl(MultiFunctionDevice):
def __init__(self, printer, scanner, fax):
self._printer = printer
self._scanner = scanner
self._fax = fax
def fax(self, document):
self._fax.fax(document)Walkthrough
Quick check
Which design follows ISP?
Run locally
bash
uv run ispExpected:
text
Hello, world!
Scanning Hello, world!
Faxing Hello, world!Source: main.py · tutorial README
Takeaway
- Fat interfaces force stub methods and lies
- Split by client need
- Compose multi-capability types from small roles