Step 1 Understand it
The problem it solves. Big 'do-everything' force to implement that make no sense for them, and every change to the big interface touches classes that don't care.
Watch it happen
Read the animation as text
- One big Machine interface: print(), scan() and fax(). Every class that implements it must write all three.
- A basic printer can only print, so it is forced to write empty methods that raise "not supported". A change to fax() still ripples into it.
- Split the interface by what clients actually need: Printer, Scanner, Fax. Each is small.
- BasicPrinter implements only Printer. An office machine implements all three. Nobody writes methods they don't support.
Picture it
classDiagram
class Printer {
<<interface>>
+print(doc)
}
class Scanner {
<<interface>>
+scan()
}
Printer <|.. BasicPrinter
Printer <|.. OfficeMachine
Scanner <|.. OfficeMachineThe idea
A giant interface forces every class that implements it to write methods it doesn't need (often empty, or throwing errors), and changes ripple into classes that don't care. Split interfaces by what their users actually need.
How it works, step by step
- Look for implementations full of empty methods or 'not supported' errors.
- Group the interface's methods by which actually call them.
- Make one small interface per group: Printer, Scanner, Fax.
- Classes implement only what they really do, and each client depends only on the small interface it uses.
Analogy
A TV remote with 80 buttons when you only need power, volume and channel. Give most people a simple remote, and an advanced one to those who need it.
Where the analogy breaks
A remote is one physical object. In code, too many tiny interfaces can be confusing too, so group methods that are always used together.
Example
A Machine interface with print(), scan() and fax() forces a basic printer to implement fax(). Split it into Printer, Scanner and Fax; an office machine implements all three.
Must-know points
- Warning sign: methods that raise NotImplementedError or do nothing.
- Split interfaces by what each client needs (role interfaces).
- Works hand in hand with single responsibility.
Common mistakes
- One interface per method everywhere, which fragments the design.
- Keeping the fat interface 'for convenience'.
from abc import ABC, abstractmethod
class Printer(ABC):
@abstractmethod
def print(self, doc): ...
class Scanner(ABC):
@abstractmethod
def scan(self): ...
class BasicPrinter(Printer): # no fake scan() needed
def print(self, doc): return f"printing {doc}"
class OfficeMachine(Printer, Scanner):
def print(self, doc): return f"printing {doc}"
def scan(self): return "scanned page"Step 2 Go further (free, optional)
Optional. The notes above are written to be enough on their own. These free resources give a second explanation and extra practice.
- Watch
-
Read
SOLID: the first 5 principles of object-oriented design
DigitalOcean, free
Step 3 Practise
Try each exercise yourself first: on paper, out loud or in code. Then open the answer and compare it with yours.
-
ExplainSay it in plain words in under a minute, with no notes.
Explain interface segregation with the TV-remote picture.
Show answer
A TV remote with 80 buttons, when most people only use power, volume and channel. Everyone has to cope with the buttons they never use, and a remote that must support all 80 is expensive to make. Better: a simple remote for most people, and an advanced one for those who want it.
The interface segregation principle says the same about interfaces: don't force a class to implement methods it doesn't need. A Machine interface with print(), scan() and fax() forces a basic printer to write fake scan() and fax() methods that just throw errors, and any change to fax() touches every printer. Split it into small interfaces by what their users actually need (Printer, Scanner, Fax), and let each class implement only the ones that are true for it.
-
DrawSketch the diagram (or class diagram) from memory.
Draw the before (Machine) and after (Printer, Scanner, Fax) designs.
Show answer
Before, one fat interface forces BasicPrinter to fake two methods that throw errors. After, each class implements only the interfaces that are true for it, and code that only prints asks for a Printer, so it works with both machines.
textBefore «interface» Machine + print() + scan() + fax() △ △ BasicPrinter OfficeMachine print() ✓ print() ✓ scan() ✗ raises scan() ✓ fax() ✗ raises fax() ✓ After «interface» «interface» «interface» Printer Scanner Fax + print() + scan() + fax() △ △ △ △ ┊ └┄┄┄┄┄┐ ┊ ┌┄┄┄┄┄┄┄┄┄┘ BasicPrinter OfficeMachine (Printer) (Printer, Scanner, Fax) -
ApplyUse it in a real design question and say exactly where it fits.
Split a interface with work(), eat() and sleep() so that a RobotWorker isn't forced to implement eat().
Show answer
Three small interfaces, one per ability. A human worker implements all three; a robot implements only Workable, so it has no fake eat() that does nothing. Code that runs a shift asks only for Workable, and the lunch break only for Eater, so each part of the program depends only on what it uses.
pythonfrom abc import ABC, abstractmethod class Workable(ABC): @abstractmethod def work(self): ... class Eater(ABC): @abstractmethod def eat(self): ... class Sleeper(ABC): @abstractmethod def sleep(self): ... class HumanWorker(Workable, Eater, Sleeper): def work(self): return "writes code" def eat(self): return "has lunch" def sleep(self): return "sleeps 8 hours" class RobotWorker(Workable): # no eat() or sleep() to fake def work(self): return "welds car doors" def run_shift(workers): # needs only work() return [worker.work() for worker in workers] def lunch_break(eaters): # needs only eat() return [eater.eat() for eater in eaters] print(run_shift([HumanWorker(), RobotWorker()])) # ['writes code', 'welds car doors'] print(lunch_break([HumanWorker()])) # ['has lunch'] -
Trade-offsSay what it costs, when not to use it, and the alternative.
How can you tell when an interface has become too small?
Show answer
Signs an interface has been split too far:
• The small interfaces are always used together. Every class implements all four, and every caller needs all four, so they are really one role.
• Functions need several parameters for one object: process(doc: Printable, s: Stapleable, c: Collatable) where all three are the same machine.
• You can't name them as roles. Good interfaces are named after what a client needs ("Printer", "PaymentMethod"); if you are reduced to "HasName" and "HasId", you are splitting by method instead of by client.
• There are more interfaces than real implementations, and each has exactly one method and one implementer.The principle is about clients: split when different callers need different parts. If no caller ever uses one part without the others, merge them back.
Step 4 Interview-ready, then prove it
Your interview answer
About 20 to 40 seconds, said out loud. Practise it until it sounds like you, not like notes.
Interface segregation means small, client-specific interfaces, so classes don't implement methods they don't need — for example separate Printer and Scanner interfaces instead of one big Machine interface.
Follow-up questions
Interface segregation or single responsibility?
Single responsibility is about why a class changes. Interface segregation is about what clients are forced to depend on. Both lead to smaller, focused pieces.
Tick each check when you can do it without notes
A topic is finished when you pass all four checks, not when you finish a video. Be strict: if you needed your notes, it is not ticked yet.
- Explain Say it in plain words in under a minute, with no notes.
- Draw Sketch the diagram (or class diagram) from memory.
- Apply Use it in a real design question and say exactly where it fits.
- Trade-offs Say what it costs, when not to use it, and the alternative.
0 of 4 checks ticked.
Saved in this browser. Back it up or move it to another device.