Interface Segregation Principle (ISP)
What is it? (The Analogy)
Imagine you go to a hardware store to buy a screwdriver. Just a simple screwdriver. But the store only sells one tool: a gigantic Swiss Army Mega-Tool 9000. It has a screwdriver, but it ALSO has a saw, a wrench, a bottle opener, a fish scaler, a magnifying glass, and a tiny pair of scissors. You just needed a screwdriver, but now you are carrying around this heavy, unwieldy monster. And every time the manufacturer updates the fish scaler, YOU have to get a new tool even though you never scale fish.
Now imagine a better hardware store that sells individual tools: a screwdriver, a wrench, a saw -- each one small, light, and perfect for its specific job. You grab the screwdriver, and you are done.
The Interface Segregation Principle says: No class should be forced to implement methods it does not use. Instead of one massive "do everything" interface, split it into smaller, focused interfaces. Give each class only the contract it actually needs.
Think of it like a restaurant menu. A good restaurant does not hand every customer the same 200-page menu that includes breakfast, lunch, dinner, catering, and the wine list. The breakfast customer gets the breakfast menu. The dinner customer gets the dinner menu. Everyone gets exactly what is relevant to them, nothing more.
Why do we need it?
Let us feel the pain. Imagine you are building a document management system, and someone designs this interface:
1// BAD EXAMPLE -- The "God Interface" that tries to do everything
2public interface SmartDevice {
3
4 // Printing capabilities
5 void print(Document doc);
6 void printDuplex(Document doc);
7
8 // Scanning capabilities
9 void scan(Document doc);
10 void scanToEmail(Document doc, String email);
11
12 // Fax capabilities (yes, fax still exists apparently)
13 void fax(Document doc, String phoneNumber);
14
15 // Copy capabilities
16 void copy(Document doc, int numCopies);
17
18 // Network capabilities
19 void connectToWifi(String networkName);
20
21 // Maintenance
22 void orderInk();
23 void runDiagnostics();
24}Now let us try to implement a simple, basic printer:
1// This poor little printer just wants to print...
2public class BasicPrinter implements SmartDevice {
3
4 @Override
5 public void print(Document doc) {
6 System.out.println("Printing: " + doc.getTitle());
7 // This is what we are here for!
8 }
9
10 @Override
11 public void printDuplex(Document doc) {
12 System.out.println("Printing both sides: " + doc.getTitle());
13 }
14
15 // Ugh, we do not scan! But we MUST implement this...
16 @Override
17 public void scan(Document doc) {
18 throw new UnsupportedOperationException("Basic printer cannot scan!");
19 }
20
21 @Override
22 public void scanToEmail(Document doc, String email) {
23 throw new UnsupportedOperationException("Basic printer cannot scan!");
24 }
25
26 // We definitely do not fax!
27 @Override
28 public void fax(Document doc, String phoneNumber) {
29 throw new UnsupportedOperationException("Basic printer cannot fax!");
30 }
31
32 @Override
33 public void copy(Document doc, int numCopies) {
34 throw new UnsupportedOperationException("Basic printer cannot copy!");
35 }
36
37 @Override
38 public void connectToWifi(String networkName) {
39 throw new UnsupportedOperationException("Basic printer has no wifi!");
40 }
41
42 @Override
43 public void orderInk() {
44 System.out.println("Ordering ink cartridge...");
45 }
46
47 @Override
48 public void runDiagnostics() {
49 System.out.println("Running basic diagnostics...");
50 }
51}The pain: Our simple BasicPrinter was forced to implement 7 methods it does not support. That is 7 methods that either throw exceptions, do nothing, or lie. Every class that implements SmartDevice must deal with ALL of this, even if it only needs a fraction. And notice how this also violates LSP -- you cannot safely substitute a BasicPrinter where the code expects scanning!
The Classic Violation -- The God Interface
The "God Interface" (also called the "fat interface") is the poster child of ISP violations. You will recognize it by these symptoms:
1// Classic God Interface symptoms:
2public interface IEverything {
3 // 20+ methods
4 // Multiple unrelated groups of behavior
5 // Most implementing classes throw UnsupportedOperationException
6 // Methods were added "just in case someone needs them"
7 // The interface name is vague: "Manager", "Handler", "Service", "Processor"
8}Real-world examples of fat interfaces that cause pain:
- A
UserServiceinterface with authentication, profile management, email, permissions, analytics, and notification methods -- all in one - A
Repositoryinterface that forces read-only views to implementsave(),update(), anddelete() - A
Workerinterface that makes office workers implementoperateHeavyMachinery()
Warning: If you see throw new UnsupportedOperationException() scattered across your codebase, you almost certainly have an ISP violation. Those exceptions are the code screaming "I was forced to implement something I should not have!"
How to Fix It -- Step by Step
- Identify the groups -- Look at your fat interface and group methods by which classes actually use them. Methods that are always used together belong in the same interface.
- Split into focused interfaces -- Create one small interface per group. Each interface should represent a single capability or role.
- Name them by capability -- Use names like
Printable,Scannable,Faxable-- names that describe what you CAN DO, not what you ARE.
- Let classes pick and choose -- Each class implements only the interfaces it genuinely supports. A basic printer implements
Printable. A multifunction device implementsPrintable,Scannable, andFaxable.
- Depend on the smallest interface possible -- When writing a method that only needs to print, accept
Printable, notSmartDevice. This keeps your code flexible and testable.
Let us Build It Together
Let us refactor our printer nightmare into a clean, ISP-compliant design. We will build an Office Equipment System step by step.
1// ========================================
2// Step 1: Split the God Interface into
3// small, focused interfaces
4// Each one represents ONE capability
5// ========================================
6
7// Can it print documents?
8public interface Printable {
9 void print(Document doc);
10 void printDuplex(Document doc);
11}
12
13// Can it scan documents?
14public interface Scannable {
15 void scan(Document doc);
16 void scanToEmail(Document doc, String email);
17}
18
19// Can it send faxes? (for the 3 companies that still use fax)
20public interface Faxable {
21 void fax(Document doc, String phoneNumber);
22}
23
24// Can it copy documents?
25public interface Copyable {
26 void copy(Document doc, int numCopies);
27}
28
29// Can it connect to a network?
30public interface NetworkConnectable {
31 void connectToWifi(String networkName);
32 boolean isConnected();
33}
34
35// Can it self-maintain?
36public interface SelfMaintainable {
37 void orderSupplies();
38 void runDiagnostics();
39}1// ========================================
2// Step 2: Basic Printer -- only implements
3// what it ACTUALLY does. No faking!
4// ========================================
5public class BasicInkjetPrinter implements Printable, SelfMaintainable {
6
7 private String model;
8
9 public BasicInkjetPrinter(String model) {
10 this.model = model;
11 }
12
13 @Override
14 public void print(Document doc) {
15 System.out.println("[" + model + "] Printing: " + doc.getTitle());
16 }
17
18 @Override
19 public void printDuplex(Document doc) {
20 System.out.println("[" + model + "] Duplex printing: " + doc.getTitle());
21 }
22
23 @Override
24 public void orderSupplies() {
25 System.out.println("[" + model + "] Ordering new ink cartridge...");
26 }
27
28 @Override
29 public void runDiagnostics() {
30 System.out.println("[" + model + "] Running print head alignment...");
31 }
32
33 // Notice: NO scan, NO fax, NO copy, NO wifi methods!
34 // We only implement what we truly support!
35}1// ========================================
2// Step 3: The fancy multifunction device
3// implements ALL capabilities it supports
4// ========================================
5public class OfficePro3000 implements Printable, Scannable, Faxable,
6 Copyable, NetworkConnectable,
7 SelfMaintainable {
8
9 private String model = "OfficePro 3000";
10 private boolean connected = false;
11
12 @Override
13 public void print(Document doc) {
14 System.out.println("[" + model + "] High-quality printing: " + doc.getTitle());
15 }
16
17 @Override
18 public void printDuplex(Document doc) {
19 System.out.println("[" + model + "] Fast duplex printing: " + doc.getTitle());
20 }
21
22 @Override
23 public void scan(Document doc) {
24 System.out.println("[" + model + "] Scanning at 600 DPI: " + doc.getTitle());
25 }
26
27 @Override
28 public void scanToEmail(Document doc, String email) {
29 System.out.println("[" + model + "] Scanning and emailing to " + email);
30 }
31
32 @Override
33 public void fax(Document doc, String phoneNumber) {
34 System.out.println("[" + model + "] Faxing to " + phoneNumber);
35 }
36
37 @Override
38 public void copy(Document doc, int numCopies) {
39 System.out.println("[" + model + "] Making " + numCopies + " copies of: " + doc.getTitle());
40 }
41
42 @Override
43 public void connectToWifi(String networkName) {
44 System.out.println("[" + model + "] Connected to WiFi: " + networkName);
45 connected = true;
46 }
47
48 @Override
49 public boolean isConnected() {
50 return connected;
51 }
52
53 @Override
54 public void orderSupplies() {
55 System.out.println("[" + model + "] Auto-ordering toner from cloud service...");
56 }
57
58 @Override
59 public void runDiagnostics() {
60 System.out.println("[" + model + "] Running full system diagnostics...");
61 }
62}1// ========================================
2// Step 4: A simple scanner with no printing!
3// ========================================
4public class PortableScanner implements Scannable {
5
6 @Override
7 public void scan(Document doc) {
8 System.out.println("[PortableScanner] Quick scan: " + doc.getTitle());
9 }
10
11 @Override
12 public void scanToEmail(Document doc, String email) {
13 System.out.println("[PortableScanner] Scan and email to " + email);
14 }
15
16 // That is it! A scanner scans. Period.
17}1// ========================================
2// Step 5: Office code depends on ONLY
3// the interface it needs -- nothing more
4// ========================================
5public class OfficeApp {
6
7 // This method only needs printing -- accepts ANYTHING printable
8 public static void printReport(Printable printer, Document report) {
9 System.out.println("\n--- Printing Report ---");
10 printer.print(report);
11 }
12
13 // This method only needs scanning -- accepts ANYTHING scannable
14 public static void digitizeDocument(Scannable scanner, Document doc) {
15 System.out.println("\n--- Digitizing Document ---");
16 scanner.scan(doc);
17 }
18
19 // This method needs scanning AND emailing -- use both interfaces
20 public static void scanAndEmail(Scannable scanner, Document doc, String email) {
21 System.out.println("\n--- Scan and Email ---");
22 scanner.scanToEmail(doc, email);
23 }
24
25 public static void main(String[] args) {
26 Document report = new Document("Q4 Sales Report");
27 Document contract = new Document("Client Contract");
28
29 BasicInkjetPrinter basicPrinter = new BasicInkjetPrinter("HP DeskJet");
30 OfficePro3000 multiFunctionDevice = new OfficePro3000();
31 PortableScanner scanner = new PortableScanner();
32
33 // Print with the basic printer -- works!
34 printReport(basicPrinter, report);
35
36 // Print with the multifunction device -- also works!
37 printReport(multiFunctionDevice, report);
38
39 // Scan with the portable scanner -- works!
40 digitizeDocument(scanner, contract);
41
42 // Scan with the multifunction device -- also works!
43 digitizeDocument(multiFunctionDevice, contract);
44
45 // You CANNOT call printReport(scanner, report) -- compile error!
46 // The scanner is not Printable, and the compiler knows it!
47 }
48}Aha moment: Notice how printReport() accepts Printable, not OfficePro3000 or SmartDevice. This means ANY future device that can print will work here -- even devices we have not invented yet. And we never force anything to pretend it can do something it cannot.
Visual Mental Model
1 BEFORE (Fat Interface): AFTER (Segregated Interfaces):
2
3 +-------------------------+ +----------+ +----------+
4 | SmartDevice | | Printable| | Scannable|
5 |-------------------------| +----------+ +----------+
6 | + print() | +----------+ +-----------+
7 | + printDuplex() | | Faxable | | Copyable |
8 | + scan() | +----------+ +-----------+
9 | + scanToEmail() | +----------------+
10 | + fax() | |NetworkConnectable|
11 | + copy() | +----------------+
12 | + connectToWifi() |
13 | + orderInk() |
14 | + runDiagnostics() |
15 +-------------------------+
16 | | BasicPrinter: OfficePro3000:
17 +---------+ +---------+ [Printable] [Printable]
18 | Basic | | Office | [SelfMaintainable] [Scannable]
19 | Printer | | Pro3000 | [Faxable]
20 +---------+ +---------+ PortableScanner: [Copyable]
21 7 methods All good [Scannable] [NetworkConnectable]
22 throw [SelfMaintainable]
23 exceptions!
24 Every class implements ONLY what it supports!Connection to SRP
ISP is like SRP for interfaces. Just as SRP says a class should have one reason to change, ISP says an interface should serve one role or capability. When you split a fat interface, you are essentially applying SRP at the interface level. The two principles reinforce each other:
- SRP asks: "Does this class have only one reason to change?"
- ISP asks: "Does this interface force classes to implement things they should not?"
Both aim to keep things focused, cohesive, and free of unnecessary baggage.
How This Connects to Design Patterns
ISP directly enables the Adapter Pattern. When you have small, focused interfaces, it is easy to write adapters that translate between them. A class that implements Printable can be adapted to work with a legacy printing system through a thin adapter -- you do not need to adapt 15 methods, just 2.
The Facade Pattern also benefits from ISP. A facade presents a simplified interface to a complex subsystem. If the subsystem is built on small interfaces, the facade can cherry-pick exactly which capabilities to expose, creating a clean and minimal surface for clients.
Common Mistakes and Gotchas
- Going too granular -- Do not create an interface for every single method (
ICanPrint,ICanPrintDuplexas separate interfaces). Group methods that are always used together. If you never callprint()without also needingprintDuplex(), they belong in one interface. - Interface explosion -- If you end up with 30 tiny interfaces, you have gone too far. Look for natural groupings. The sweet spot is 3-7 methods per interface.
- Renaming without restructuring -- Splitting
SmartDeviceintoSmartDevice1andSmartDevice2misses the point. Name interfaces by CAPABILITY:Printable,Scannable,Faxable. - Forgetting to update dependencies -- After splitting, make sure your methods accept the smallest interface they need. If a method only prints, change its parameter from
SmartDevicetoPrintable. - Marker interfaces with no methods -- An interface with zero methods (just used as a "tag") is sometimes useful, but do not confuse it with ISP. ISP is about not forcing unnecessary method implementations.
Interview Tip
When you see a class with several methods that throw UnsupportedOperationException or have empty bodies, point it out immediately: "This looks like an ISP violation -- the interface is forcing this class to implement methods it does not support. I would split the interface into smaller, role-based interfaces." Then sketch the split on the whiteboard. This demonstrates that you understand interface design, not just class design. Bonus points: mention that ISP makes testing easier because you can mock a small interface instead of a giant one with 15 methods.
Quick Quiz
- You have a
Vehicleinterface with methods:drive(),fly(),sail(), andrefuel(). ACarclass implements this interface. What is wrong, and how would you fix it?
- Your team has an interface
DataStorewith methods:read(),write(),delete(), andbackup(). AReadOnlyCacheclass implementsDataStoreand throws exceptions forwrite(),delete(), andbackup(). Redesign this.
- Is it possible to have TOO MANY small interfaces? When would splitting go too far?
Summary -- Key Takeaways
- No class should be forced to implement methods it does not use. Fat interfaces create fake implementations, wasted code, and runtime errors.
- Split big interfaces into small, role-based ones. Name them by capability:
Printable,Scannable,Flyable. Classes then implement only what they truly support. - ISP is SRP for interfaces. Just as classes should have one reason to change, interfaces should serve one role.
- Depend on the smallest interface you need. If a method only needs to print, accept
Printable-- not the 15-methodSmartDevicemonolith. This keeps your code flexible, testable, and future-proof.