Interface Segregation Principle
The Interface Segregation Principle (ISP) states that clients should not be forced to depend on interfaces they don’t use. Instead of one fat interface, many small, specific interfaces are preferred.
This principle helps prevent the creation of “fat” or “bloated” interfaces that force implementing classes to provide empty implementations for methods they don’t need.
Understanding the Principle
Section titled “Understanding the Principle”The Interface Segregation Principle ensures that:
- Interfaces are focused - Each interface has a single, well-defined purpose
- No forced implementations - Classes don’t implement methods they don’t need
- Better cohesion - Related methods are grouped together
- Loose coupling - Clients depend only on what they actually use
In simple terms: Don’t force a class to implement methods it doesn’t need!
Example 1: Worker Interface Problem
Section titled “Example 1: Worker Interface Problem”Consider a system with different types of workers. Let’s see what happens when we create a fat interface.
Violating ISP (Bad Approach)
Section titled “Violating ISP (Bad Approach)”from abc import ABC, abstractmethod
class Worker(ABC): """❌ Fat interface - violates ISP""" @abstractmethod def work(self): """All workers can work""" pass
@abstractmethod def eat(self): """❌ Problem: Not all workers eat!""" pass
@abstractmethod def sleep(self): """❌ Problem: Not all workers sleep!""" pass
class HumanWorker(Worker): """Human worker - can do all three""" def work(self): print("Human is working...")
def eat(self): print("Human is eating...")
def sleep(self): print("Human is sleeping...")
class RobotWorker(Worker): """❌ Robot worker - forced to implement methods it doesn't need!""" def work(self): print("Robot is working...")
def eat(self): """❌ Robots don't eat! Empty implementation""" raise NotImplementedError("Robots don't eat!")
def sleep(self): """❌ Robots don't sleep! Empty implementation""" raise NotImplementedError("Robots don't sleep!")
# Usagehuman = HumanWorker()human.work() # ✅ Workshuman.eat() # ✅ Workshuman.sleep() # ✅ Works
robot = RobotWorker()robot.work() # ✅ Worksrobot.eat() # ❌ Breaks! Robots don't eatrobot.sleep() # ❌ Breaks! Robots don't sleep// ❌ Fat interface - violates ISPpublic interface Worker { // All workers can work void work();
// ❌ Problem: Not all workers eat! void eat();
// ❌ Problem: Not all workers sleep! void sleep();}
// Human worker - can do all threepublic class HumanWorker implements Worker { @Override public void work() { System.out.println("Human is working..."); }
@Override public void eat() { System.out.println("Human is eating..."); }
@Override public void sleep() { System.out.println("Human is sleeping..."); }}
// ❌ Robot worker - forced to implement methods it doesn't need!public class RobotWorker implements Worker { @Override public void work() { System.out.println("Robot is working..."); }
// ❌ Robots don't eat! Empty implementation @Override public void eat() { throw new UnsupportedOperationException("Robots don't eat!"); }
// ❌ Robots don't sleep! Empty implementation @Override public void sleep() { throw new UnsupportedOperationException("Robots don't sleep!"); }}
// Usagepublic class Main { public static void main(String[] args) { HumanWorker human = new HumanWorker(); human.work(); // ✅ Works human.eat(); // ✅ Works human.sleep(); // ✅ Works
RobotWorker robot = new RobotWorker(); robot.work(); // ✅ Works robot.eat(); // ❌ Breaks! Robots don't eat robot.sleep(); // ❌ Breaks! Robots don't sleep }}// ❌ Fat interface - violates ISPinterface Worker { // All workers can work work(): void;
// ❌ Problem: Not all workers eat! eat(): void;
// ❌ Problem: Not all workers sleep! sleep(): void;}
// Human worker - can do all threeclass HumanWorker implements Worker { work(): void { console.log("Human is working..."); }
eat(): void { console.log("Human is eating..."); }
sleep(): void { console.log("Human is sleeping..."); }}
// ❌ Robot worker - forced to implement methods it doesn't need!class RobotWorker implements Worker { work(): void { console.log("Robot is working..."); }
// ❌ Robots don't eat! Empty implementation eat(): void { throw new Error("Robots don't eat!"); }
// ❌ Robots don't sleep! Empty implementation sleep(): void { throw new Error("Robots don't sleep!"); }}
// Usageconst human = new HumanWorker();human.work(); // ✅ Workshuman.eat(); // ✅ Workshuman.sleep(); // ✅ Works
const robot = new RobotWorker();robot.work(); // ✅ Worksrobot.eat(); // ❌ Breaks! Robots don't eatrobot.sleep(); // ❌ Breaks! Robots don't sleep#include <iostream>#include <stdexcept>
// ❌ Fat interface - violates ISPclass Worker {public: virtual ~Worker() = default;
// All workers can work virtual void work() = 0;
// ❌ Problem: Not all workers eat! virtual void eat() = 0;
// ❌ Problem: Not all workers sleep! virtual void sleep() = 0;};
// Human worker - can do all threeclass HumanWorker : public Worker {public: void work() override { std::cout << "Human is working..." << std::endl; }
void eat() override { std::cout << "Human is eating..." << std::endl; }
void sleep() override { std::cout << "Human is sleeping..." << std::endl; }};
// ❌ Robot worker - forced to implement methods it doesn't need!class RobotWorker : public Worker {public: void work() override { std::cout << "Robot is working..." << std::endl; }
// ❌ Robots don't eat! Empty implementation void eat() override { throw std::runtime_error("Robots don't eat!"); }
// ❌ Robots don't sleep! Empty implementation void sleep() override { throw std::runtime_error("Robots don't sleep!"); }};
int main() { // Usage HumanWorker human; human.work(); // ✅ Works human.eat(); // ✅ Works human.sleep(); // ✅ Works
RobotWorker robot; robot.work(); // ✅ Works // robot.eat(); // ❌ Breaks! Robots don't eat // robot.sleep(); // ❌ Breaks! Robots don't sleep
return 0;}using System;
// ❌ Fat interface - violates ISPpublic interface IWorker{ // All workers can work void Work();
// ❌ Problem: Not all workers eat! void Eat();
// ❌ Problem: Not all workers sleep! void Sleep();}
// Human worker - can do all threepublic class HumanWorker : IWorker{ public void Work() { Console.WriteLine("Human is working..."); }
public void Eat() { Console.WriteLine("Human is eating..."); }
public void Sleep() { Console.WriteLine("Human is sleeping..."); }}
// ❌ Robot worker - forced to implement methods it doesn't need!public class RobotWorker : IWorker{ public void Work() { Console.WriteLine("Robot is working..."); }
// ❌ Robots don't eat! Empty implementation public void Eat() { throw new NotSupportedException("Robots don't eat!"); }
// ❌ Robots don't sleep! Empty implementation public void Sleep() { throw new NotSupportedException("Robots don't sleep!"); }}
class Program{ static void Main() { // Usage HumanWorker human = new HumanWorker(); human.Work(); // ✅ Works human.Eat(); // ✅ Works human.Sleep(); // ✅ Works
RobotWorker robot = new RobotWorker(); robot.Work(); // ✅ Works // robot.Eat(); // ❌ Breaks! Robots don't eat // robot.Sleep(); // ❌ Breaks! Robots don't sleep }}package main
import ( "errors" "fmt")
// ❌ Fat interface - violates ISPtype Worker interface { Work() Eat() error // ❌ Not all workers eat! Sleep() error // ❌ Not all workers sleep!}
type HumanWorker struct{}
func (h *HumanWorker) Work() { fmt.Println("Human is working...") }func (h *HumanWorker) Eat() error { fmt.Println("Human is eating..."); return nil }func (h *HumanWorker) Sleep() error { fmt.Println("Human is sleeping..."); return nil }
// ❌ Robot forced to implement methods it doesn't need!type RobotWorker struct{}
func (r *RobotWorker) Work() { fmt.Println("Robot is working...") }func (r *RobotWorker) Eat() error { return errors.New("robots don't eat") } // ❌func (r *RobotWorker) Sleep() error { return errors.New("robots don't sleep") } // ❌
func main() { human := &HumanWorker{} human.Work() human.Eat() human.Sleep()
robot := &RobotWorker{} robot.Work() // robot.Eat() // ❌ Error: robots don't eat // robot.Sleep() // ❌ Error: robots don't sleep}trait Worker { fn work(&self); fn eat(&self); fn sleep(&self);}struct Robot;impl Worker for Robot { fn work(&self) { println!("Robot working"); } fn eat(&self) { panic!("Robot cannot eat"); } fn sleep(&self) { panic!("Robot cannot sleep"); }}// A fat interface forces unsupported behavior.Following ISP (Good Approach)
Section titled “Following ISP (Good Approach)”from abc import ABC, abstractmethod
class Workable(ABC): """Focused interface - only work capability""" @abstractmethod def work(self): """All workers can work""" pass
class Eatable(ABC): """Focused interface - only eating capability""" @abstractmethod def eat(self): """Only workers that eat implement this""" pass
class Sleepable(ABC): """Focused interface - only sleeping capability""" @abstractmethod def sleep(self): """Only workers that sleep implement this""" pass
class HumanWorker(Workable, Eatable, Sleepable): """Human implements all interfaces it needs""" def work(self): print("Human is working...")
def eat(self): print("Human is eating...")
def sleep(self): print("Human is sleeping...")
class RobotWorker(Workable): """Robot only implements what it needs - work""" def work(self): print("Robot is working...") # No eat() or sleep() - correct!
# Usage - Clean and focused!human = HumanWorker()human.work() # ✅ Workshuman.eat() # ✅ Workshuman.sleep() # ✅ Works
robot = RobotWorker()robot.work() # ✅ Works# robot.eat() # ✅ Type error - prevents calling methods robot doesn't have# robot.sleep() # ✅ Type error - prevents calling methods robot doesn't have// Focused interface - only work capabilitypublic interface Workable { // All workers can work void work();}
// Focused interface - only eating capabilitypublic interface Eatable { // Only workers that eat implement this void eat();}
// Focused interface - only sleeping capabilitypublic interface Sleepable { // Only workers that sleep implement this void sleep();}
// Human implements all interfaces it needspublic class HumanWorker implements Workable, Eatable, Sleepable { @Override public void work() { System.out.println("Human is working..."); }
@Override public void eat() { System.out.println("Human is eating..."); }
@Override public void sleep() { System.out.println("Human is sleeping..."); }}
// Robot only implements what it needs - workpublic class RobotWorker implements Workable { @Override public void work() { System.out.println("Robot is working..."); } // No eat() or sleep() - correct!}
// Usage - Clean and focused!public class Main { public static void main(String[] args) { HumanWorker human = new HumanWorker(); human.work(); // ✅ Works human.eat(); // ✅ Works human.sleep(); // ✅ Works
RobotWorker robot = new RobotWorker(); robot.work(); // ✅ Works // robot.eat(); // ✅ Compile error - prevents calling methods robot doesn't have // robot.sleep(); // ✅ Compile error - prevents calling methods robot doesn't have }}// Focused interface - only work capabilityinterface Workable { /** All workers can work */ work(): void;}
// Focused interface - only eating capabilityinterface Eatable { /** Only workers that eat implement this */ eat(): void;}
// Focused interface - only sleeping capabilityinterface Sleepable { /** Only workers that sleep implement this */ sleep(): void;}
// Human implements all interfaces it needsclass HumanWorker implements Workable, Eatable, Sleepable { work(): void { console.log("Human is working..."); }
eat(): void { console.log("Human is eating..."); }
sleep(): void { console.log("Human is sleeping..."); }}
// Robot only implements what it needs - workclass RobotWorker implements Workable { work(): void { console.log("Robot is working..."); } // No eat() or sleep() - correct!}
// Usage - Clean and focused!const human = new HumanWorker();human.work(); // ✅ Workshuman.eat(); // ✅ Workshuman.sleep(); // ✅ Works
const robot = new RobotWorker();robot.work(); // ✅ Works// robot.eat(); // ✅ Type error - prevents calling methods robot doesn't have// robot.sleep(); // ✅ Type error - prevents calling methods robot doesn't have#include <iostream>
// Focused interface - only work capabilityclass Workable {public: virtual ~Workable() = default; // All workers can work virtual void work() = 0;};
// Focused interface - only eating capabilityclass Eatable {public: virtual ~Eatable() = default; // Only workers that eat implement this virtual void eat() = 0;};
// Focused interface - only sleeping capabilityclass Sleepable {public: virtual ~Sleepable() = default; // Only workers that sleep implement this virtual void sleep() = 0;};
// Human implements all interfaces it needsclass HumanWorker : public Workable, public Eatable, public Sleepable {public: void work() override { std::cout << "Human is working..." << std::endl; }
void eat() override { std::cout << "Human is eating..." << std::endl; }
void sleep() override { std::cout << "Human is sleeping..." << std::endl; }};
// Robot only implements what it needs - workclass RobotWorker : public Workable {public: void work() override { std::cout << "Robot is working..." << std::endl; } // No eat() or sleep() - correct!};
int main() { // Usage - Clean and focused! HumanWorker human; human.work(); // ✅ Works human.eat(); // ✅ Works human.sleep(); // ✅ Works
RobotWorker robot; robot.work(); // ✅ Works // robot.eat(); // ✅ Compile error - prevents calling methods robot doesn't have // robot.sleep(); // ✅ Compile error - prevents calling methods robot doesn't have
return 0;}using System;
// Focused interface - only work capabilitypublic interface IWorkable{ // All workers can work void Work();}
// Focused interface - only eating capabilitypublic interface IEatable{ // Only workers that eat implement this void Eat();}
// Focused interface - only sleeping capabilitypublic interface ISleepable{ // Only workers that sleep implement this void Sleep();}
// Human implements all interfaces it needspublic class HumanWorker : IWorkable, IEatable, ISleepable{ public void Work() { Console.WriteLine("Human is working..."); }
public void Eat() { Console.WriteLine("Human is eating..."); }
public void Sleep() { Console.WriteLine("Human is sleeping..."); }}
// Robot only implements what it needs - workpublic class RobotWorker : IWorkable{ public void Work() { Console.WriteLine("Robot is working..."); } // No Eat() or Sleep() - correct!}
class Program{ static void Main() { // Usage - Clean and focused! HumanWorker human = new HumanWorker(); human.Work(); // ✅ Works human.Eat(); // ✅ Works human.Sleep(); // ✅ Works
RobotWorker robot = new RobotWorker(); robot.Work(); // ✅ Works // robot.Eat(); // ✅ Compile error - prevents calling methods robot doesn't have // robot.Sleep(); // ✅ Compile error - prevents calling methods robot doesn't have }}package main
import "fmt"
// Focused interfacestype Workable interface{ Work() }type Eatable interface{ Eat() }type Sleepable interface{ Sleep() }
// Human implements all interfaces it needstype HumanWorker struct{}
func (h *HumanWorker) Work() { fmt.Println("Human is working...") }func (h *HumanWorker) Eat() { fmt.Println("Human is eating...") }func (h *HumanWorker) Sleep() { fmt.Println("Human is sleeping...") }
// Robot only implements what it needstype RobotWorker struct{}
func (r *RobotWorker) Work() { fmt.Println("Robot is working...") }// No Eat() or Sleep() - correct!
func main() { human := &HumanWorker{} human.Work() human.Eat() human.Sleep()
robot := &RobotWorker{} robot.Work() // robot.Eat() // ✅ Compile error - RobotWorker has no Eat method}trait Workable { fn work(&self);}trait Eatable { fn eat(&self);}trait Sleepable { fn sleep(&self);}struct Human;struct Robot;impl Workable for Human { fn work(&self) { println!("Human working"); }}impl Eatable for Human { fn eat(&self) { println!("Human eating"); }}impl Sleepable for Human { fn sleep(&self) { println!("Human sleeping"); }}impl Workable for Robot { fn work(&self) { println!("Robot working"); }}Why this follows ISP:
- Each interface has a single, focused responsibility
- Classes implement only the interfaces they need
- No empty implementations or exceptions
- Changes to one interface don’t affect unrelated classes
Example 2: Document Management System
Section titled “Example 2: Document Management System”Consider a document management system with different types of devices that can interact with documents.
Violating ISP (Bad Approach)
Section titled “Violating ISP (Bad Approach)”from abc import ABC, abstractmethod
class Device(ABC): """❌ Fat interface - violates ISP""" @abstractmethod def print(self, document: str): """Print a document""" pass
@abstractmethod def scan(self) -> str: """Scan a document""" pass
@abstractmethod def fax(self, document: str): """Fax a document""" pass
@abstractmethod def email(self, document: str): """Email a document""" pass
class Printer(Device): """Printer - can print, but not scan/fax/email""" def print(self, document: str): print(f"Printing: {document}")
def scan(self) -> str: """❌ Printer can't scan!""" raise NotImplementedError("This printer cannot scan!")
def fax(self, document: str): """❌ Printer can't fax!""" raise NotImplementedError("This printer cannot fax!")
def email(self, document: str): """❌ Printer can't email!""" raise NotImplementedError("This printer cannot email!")
class Scanner(Device): """Scanner - can scan, but not print/fax/email""" def print(self, document: str): """❌ Scanner can't print!""" raise NotImplementedError("This scanner cannot print!")
def scan(self) -> str: return f"Scanned: {document}"
def fax(self, document: str): """❌ Scanner can't fax!""" raise NotImplementedError("This scanner cannot fax!")
def email(self, document: str): """❌ Scanner can't email!""" raise NotImplementedError("This scanner cannot email!")
# Usage - Lots of exceptions!printer = Printer()printer.print("doc.pdf") # ✅ Worksprinter.scan() # ❌ Raises exception!// ❌ Fat interface - violates ISPpublic interface Device { // Print a document void print(String document);
// Scan a document String scan();
// Fax a document void fax(String document);
// Email a document void email(String document);}
// Printer - can print, but not scan/fax/emailpublic class Printer implements Device { @Override public void print(String document) { System.out.println("Printing: " + document); }
// ❌ Printer can't scan! @Override public String scan() { throw new UnsupportedOperationException("This printer cannot scan!"); }
// ❌ Printer can't fax! @Override public void fax(String document) { throw new UnsupportedOperationException("This printer cannot fax!"); }
// ❌ Printer can't email! @Override public void email(String document) { throw new UnsupportedOperationException("This printer cannot email!"); }}
// Scanner - can scan, but not print/fax/emailpublic class Scanner implements Device { // ❌ Scanner can't print! @Override public void print(String document) { throw new UnsupportedOperationException("This scanner cannot print!"); }
@Override public String scan() { return "Scanned: " + document; }
// ❌ Scanner can't fax! @Override public void fax(String document) { throw new UnsupportedOperationException("This scanner cannot fax!"); }
// ❌ Scanner can't email! @Override public void email(String document) { throw new UnsupportedOperationException("This scanner cannot email!"); }}
// Usage - Lots of exceptions!public class Main { public static void main(String[] args) { Printer printer = new Printer(); printer.print("doc.pdf"); // ✅ Works printer.scan(); // ❌ Throws exception! }}// ❌ Fat interface - violates ISPinterface Device { // Print a document print(document: string): void;
// Scan a document scan(): string;
// Fax a document fax(document: string): void;
// Email a document email(document: string): void;}
// Printer - can print, but not scan/fax/emailclass Printer implements Device { print(document: string): void { console.log(`Printing: ${document}`); }
// ❌ Printer can't scan! scan(): string { throw new Error("This printer cannot scan!"); }
// ❌ Printer can't fax! fax(document: string): void { throw new Error("This printer cannot fax!"); }
// ❌ Printer can't email! email(document: string): void { throw new Error("This printer cannot email!"); }}
// Scanner - can scan, but not print/fax/emailclass Scanner implements Device { // ❌ Scanner can't print! print(document: string): void { throw new Error("This scanner cannot print!"); }
scan(): string { return "Scanned document content"; }
// ❌ Scanner can't fax! fax(document: string): void { throw new Error("This scanner cannot fax!"); }
// ❌ Scanner can't email! email(document: string): void { throw new Error("This scanner cannot email!"); }}
// Usage - Lots of exceptions!const printer = new Printer();printer.print("doc.pdf"); // ✅ Works// printer.scan(); // ❌ Throws exception!#include <string>#include <iostream>#include <stdexcept>
// ❌ Fat interface - violates ISPclass Device {public: virtual ~Device() = default;
// Print a document virtual void print(const std::string& document) = 0;
// Scan a document virtual std::string scan() = 0;
// Fax a document virtual void fax(const std::string& document) = 0;
// Email a document virtual void email(const std::string& document) = 0;};
// Printer - can print, but not scan/fax/emailclass Printer : public Device {public: void print(const std::string& document) override { std::cout << "Printing: " << document << std::endl; }
// ❌ Printer can't scan! std::string scan() override { throw std::runtime_error("This printer cannot scan!"); }
// ❌ Printer can't fax! void fax(const std::string& document) override { throw std::runtime_error("This printer cannot fax!"); }
// ❌ Printer can't email! void email(const std::string& document) override { throw std::runtime_error("This printer cannot email!"); }};
// Scanner - can scan, but not print/fax/emailclass Scanner : public Device {public: // ❌ Scanner can't print! void print(const std::string& document) override { throw std::runtime_error("This scanner cannot print!"); }
std::string scan() override { return "Scanned document content"; }
// ❌ Scanner can't fax! void fax(const std::string& document) override { throw std::runtime_error("This scanner cannot fax!"); }
// ❌ Scanner can't email! void email(const std::string& document) override { throw std::runtime_error("This scanner cannot email!"); }};
int main() { // Usage - Lots of exceptions! Printer printer; printer.print("doc.pdf"); // ✅ Works // printer.scan(); // ❌ Throws exception!
return 0;}using System;
// ❌ Fat interface - violates ISPpublic interface IDevice{ // Print a document void Print(string document);
// Scan a document string Scan();
// Fax a document void Fax(string document);
// Email a document void Email(string document);}
// Printer - can print, but not scan/fax/emailpublic class Printer : IDevice{ public void Print(string document) { Console.WriteLine($"Printing: {document}"); }
// ❌ Printer can't scan! public string Scan() { throw new NotSupportedException("This printer cannot scan!"); }
// ❌ Printer can't fax! public void Fax(string document) { throw new NotSupportedException("This printer cannot fax!"); }
// ❌ Printer can't email! public void Email(string document) { throw new NotSupportedException("This printer cannot email!"); }}
// Scanner - can scan, but not print/fax/emailpublic class Scanner : IDevice{ // ❌ Scanner can't print! public void Print(string document) { throw new NotSupportedException("This scanner cannot print!"); }
public string Scan() { return "Scanned document content"; }
// ❌ Scanner can't fax! public void Fax(string document) { throw new NotSupportedException("This scanner cannot fax!"); }
// ❌ Scanner can't email! public void Email(string document) { throw new NotSupportedException("This scanner cannot email!"); }}
class Program{ static void Main() { // Usage - Lots of exceptions! Printer printer = new Printer(); printer.Print("doc.pdf"); // ✅ Works // printer.Scan(); // ❌ Throws exception! }}package main
import ( "errors" "fmt")
// ❌ Fat interface - violates ISPtype Device interface { Print(document string) error Scan() (string, error) Fax(document string) error Email(document string) error}
type Printer struct{}
func (p *Printer) Print(doc string) error { fmt.Printf("Printing: %s\n", doc); return nil }func (p *Printer) Scan() (string, error) { return "", errors.New("this printer cannot scan") } // ❌func (p *Printer) Fax(doc string) error { return errors.New("this printer cannot fax") } // ❌func (p *Printer) Email(doc string) error { return errors.New("this printer cannot email") } // ❌
type Scanner struct{}
func (s *Scanner) Print(doc string) error { return errors.New("this scanner cannot print") } // ❌func (s *Scanner) Scan() (string, error) { return "Scanned document content", nil }func (s *Scanner) Fax(doc string) error { return errors.New("this scanner cannot fax") } // ❌func (s *Scanner) Email(doc string) error { return errors.New("this scanner cannot email") } // ❌
func main() { printer := &Printer{} printer.Print("doc.pdf") // ✅ Works // printer.Scan() // ❌ Error!}trait MultiFunctionDevice { fn print(&self); fn scan(&self); fn fax(&self);}struct SimplePrinter;impl MultiFunctionDevice for SimplePrinter { fn print(&self) { println!("Printing"); } fn scan(&self) { panic!("Scan not supported"); } fn fax(&self) { panic!("Fax not supported"); }}// SimplePrinter is forced to fake unsupported operations.Following ISP (Good Approach)
Section titled “Following ISP (Good Approach)”from abc import ABC, abstractmethod
class Printable(ABC): """Focused interface - printing capability""" @abstractmethod def print(self, document: str): """Print a document""" pass
class Scannable(ABC): """Focused interface - scanning capability""" @abstractmethod def scan(self) -> str: """Scan a document""" pass
class Faxable(ABC): """Focused interface - faxing capability""" @abstractmethod def fax(self, document: str): """Fax a document""" pass
class Emailable(ABC): """Focused interface - emailing capability""" @abstractmethod def email(self, document: str): """Email a document""" pass
class Printer(Printable): """Printer only implements what it can do""" def print(self, document: str): print(f"Printing: {document}")
class Scanner(Scannable): """Scanner only implements what it can do""" def scan(self) -> str: return "Scanned document content"
class MultiFunctionDevice(Printable, Scannable, Faxable, Emailable): """Multi-function device implements all interfaces it supports""" def print(self, document: str): print(f"Printing: {document}")
def scan(self) -> str: return "Scanned document content"
def fax(self, document: str): print(f"Faxing: {document}")
def email(self, document: str): print(f"Emailing: {document}")
# Helper functions that work with specific interfacesdef print_document(device: Printable, document: str): """Works with any Printable device""" device.print(document)
def scan_document(device: Scannable) -> str: """Works with any Scannable device""" return device.scan()
# Usage - Clean and type-safe!printer = Printer()scanner = Scanner()multi_device = MultiFunctionDevice()
print_document(printer, "doc.pdf") # ✅ Worksprint_document(multi_device, "doc.pdf") # ✅ Works# print_document(scanner, "doc.pdf") # ✅ Type error - scanner can't print
scan_document(scanner) # ✅ Worksscan_document(multi_device) # ✅ Works# scan_document(printer) # ✅ Type error - printer can't scan// Focused interface - printing capabilitypublic interface Printable { // Print a document void print(String document);}
// Focused interface - scanning capabilitypublic interface Scannable { // Scan a document String scan();}
// Focused interface - faxing capabilitypublic interface Faxable { // Fax a document void fax(String document);}
// Focused interface - emailing capabilitypublic interface Emailable { // Email a document void email(String document);}
// Printer only implements what it can dopublic class Printer implements Printable { @Override public void print(String document) { System.out.println("Printing: " + document); }}
// Scanner only implements what it can dopublic class Scanner implements Scannable { @Override public String scan() { return "Scanned document content"; }}
// Multi-function device implements all interfaces it supportspublic class MultiFunctionDevice implements Printable, Scannable, Faxable, Emailable { @Override public void print(String document) { System.out.println("Printing: " + document); }
@Override public String scan() { return "Scanned document content"; }
@Override public void fax(String document) { System.out.println("Faxing: " + document); }
@Override public void email(String document) { System.out.println("Emailing: " + document); }}
// Helper functions that work with specific interfacespublic class DeviceService { // Works with any Printable device public static void printDocument(Printable device, String document) { device.print(document); }
// Works with any Scannable device public static String scanDocument(Scannable device) { return device.scan(); }
public static void main(String[] args) { // Usage - Clean and type-safe! Printer printer = new Printer(); Scanner scanner = new Scanner(); MultiFunctionDevice multiDevice = new MultiFunctionDevice();
printDocument(printer, "doc.pdf"); // ✅ Works printDocument(multiDevice, "doc.pdf"); // ✅ Works // printDocument(scanner, "doc.pdf"); // ✅ Compile error - scanner can't print
scanDocument(scanner); // ✅ Works scanDocument(multiDevice); // ✅ Works // scanDocument(printer); // ✅ Compile error - printer can't scan }}// Focused interface - printing capabilityinterface Printable { /** Print a document */ print(document: string): void;}
// Focused interface - scanning capabilityinterface Scannable { /** Scan a document */ scan(): string;}
// Focused interface - faxing capabilityinterface Faxable { /** Fax a document */ fax(document: string): void;}
// Focused interface - emailing capabilityinterface Emailable { /** Email a document */ email(document: string): void;}
// Printer only implements what it can doclass Printer implements Printable { print(document: string): void { console.log(`Printing: ${document}`); }}
// Scanner only implements what it can doclass Scanner implements Scannable { scan(): string { return "Scanned document content"; }}
// Multi-function device implements all interfaces it supportsclass MultiFunctionDevice implements Printable, Scannable, Faxable, Emailable { print(document: string): void { console.log(`Printing: ${document}`); }
scan(): string { return "Scanned document content"; }
fax(document: string): void { console.log(`Faxing: ${document}`); }
email(document: string): void { console.log(`Emailing: ${document}`); }}
// Helper functions that work with specific interfacesfunction printDocument(device: Printable, document: string): void { /** Works with any Printable device */ device.print(document);}
function scanDocument(device: Scannable): string { /** Works with any Scannable device */ return device.scan();}
// Usage - Clean and type-safe!const printer = new Printer();const scanner = new Scanner();const multiDevice = new MultiFunctionDevice();
printDocument(printer, "doc.pdf"); // ✅ WorksprintDocument(multiDevice, "doc.pdf"); // ✅ Works// printDocument(scanner, "doc.pdf"); // ✅ Type error - scanner can't print
scanDocument(scanner); // ✅ WorksscanDocument(multiDevice); // ✅ Works// scanDocument(printer); // ✅ Type error - printer can't scan#include <string>#include <iostream>
// Focused interface - printing capabilityclass Printable {public: virtual ~Printable() = default; // Print a document virtual void print(const std::string& document) = 0;};
// Focused interface - scanning capabilityclass Scannable {public: virtual ~Scannable() = default; // Scan a document virtual std::string scan() = 0;};
// Focused interface - faxing capabilityclass Faxable {public: virtual ~Faxable() = default; // Fax a document virtual void fax(const std::string& document) = 0;};
// Focused interface - emailing capabilityclass Emailable {public: virtual ~Emailable() = default; // Email a document virtual void email(const std::string& document) = 0;};
// Printer only implements what it can doclass Printer : public Printable {public: void print(const std::string& document) override { std::cout << "Printing: " << document << std::endl; }};
// Scanner only implements what it can doclass Scanner : public Scannable {public: std::string scan() override { return "Scanned document content"; }};
// Multi-function device implements all interfaces it supportsclass MultiFunctionDevice : public Printable, public Scannable, public Faxable, public Emailable {public: void print(const std::string& document) override { std::cout << "Printing: " << document << std::endl; }
std::string scan() override { return "Scanned document content"; }
void fax(const std::string& document) override { std::cout << "Faxing: " << document << std::endl; }
void email(const std::string& document) override { std::cout << "Emailing: " << document << std::endl; }};
// Helper functions that work with specific interfacesvoid printDocument(Printable& device, const std::string& document) { // Works with any Printable device device.print(document);}
std::string scanDocument(Scannable& device) { // Works with any Scannable device return device.scan();}
int main() { // Usage - Clean and type-safe! Printer printer; Scanner scanner; MultiFunctionDevice multiDevice;
printDocument(printer, "doc.pdf"); // ✅ Works printDocument(multiDevice, "doc.pdf"); // ✅ Works // printDocument(scanner, "doc.pdf"); // ✅ Compile error - scanner can't print
scanDocument(scanner); // ✅ Works scanDocument(multiDevice); // ✅ Works // scanDocument(printer); // ✅ Compile error - printer can't scan
return 0;}using System;
// Focused interface - printing capabilitypublic interface IPrintable{ // Print a document void Print(string document);}
// Focused interface - scanning capabilitypublic interface IScannable{ // Scan a document string Scan();}
// Focused interface - faxing capabilitypublic interface IFaxable{ // Fax a document void Fax(string document);}
// Focused interface - emailing capabilitypublic interface IEmailable{ // Email a document void Email(string document);}
// Printer only implements what it can dopublic class Printer : IPrintable{ public void Print(string document) { Console.WriteLine($"Printing: {document}"); }}
// Scanner only implements what it can dopublic class Scanner : IScannable{ public string Scan() { return "Scanned document content"; }}
// Multi-function device implements all interfaces it supportspublic class MultiFunctionDevice : IPrintable, IScannable, IFaxable, IEmailable{ public void Print(string document) { Console.WriteLine($"Printing: {document}"); }
public string Scan() { return "Scanned document content"; }
public void Fax(string document) { Console.WriteLine($"Faxing: {document}"); }
public void Email(string document) { Console.WriteLine($"Emailing: {document}"); }}
// Helper functions that work with specific interfacespublic class DeviceService{ // Works with any Printable device public static void PrintDocument(IPrintable device, string document) { device.Print(document); }
// Works with any Scannable device public static string ScanDocument(IScannable device) { return device.Scan(); }}
class Program{ static void Main() { // Usage - Clean and type-safe! Printer printer = new Printer(); Scanner scanner = new Scanner(); MultiFunctionDevice multiDevice = new MultiFunctionDevice();
DeviceService.PrintDocument(printer, "doc.pdf"); // ✅ Works DeviceService.PrintDocument(multiDevice, "doc.pdf"); // ✅ Works // DeviceService.PrintDocument(scanner, "doc.pdf"); // ✅ Compile error - scanner can't print
DeviceService.ScanDocument(scanner); // ✅ Works DeviceService.ScanDocument(multiDevice); // ✅ Works // DeviceService.ScanDocument(printer); // ✅ Compile error - printer can't scan }}package main
import "fmt"
// Focused interfacestype Printable interface{ Print(document string) }type Scannable interface{ Scan() string }type Faxable interface{ Fax(document string) }type Emailable interface{ Email(document string) }
type Printer struct{}
func (p *Printer) Print(doc string) { fmt.Printf("Printing: %s\n", doc) }
type Scanner struct{}
func (s *Scanner) Scan() string { return "Scanned document content" }
// Multi-function device implements all interfaces it supportstype MultiFunctionDevice struct{}
func (m *MultiFunctionDevice) Print(doc string) { fmt.Printf("Printing: %s\n", doc) }func (m *MultiFunctionDevice) Scan() string { return "Scanned document content" }func (m *MultiFunctionDevice) Fax(doc string) { fmt.Printf("Faxing: %s\n", doc) }func (m *MultiFunctionDevice) Email(doc string) { fmt.Printf("Emailing: %s\n", doc) }
type DeviceService struct{}
func (d *DeviceService) PrintDocument(device Printable, doc string) { device.Print(doc) }func (d *DeviceService) ScanDocument(device Scannable) string { return device.Scan() }
func main() { printer := &Printer{} scanner := &Scanner{} multi := &MultiFunctionDevice{} svc := &DeviceService{}
svc.PrintDocument(printer, "doc.pdf") // ✅ Works svc.PrintDocument(multi, "doc.pdf") // ✅ Works // svc.PrintDocument(scanner, "doc.pdf") // ✅ Compile error
svc.ScanDocument(scanner) // ✅ Works svc.ScanDocument(multi) // ✅ Works // svc.ScanDocument(printer) // ✅ Compile error}trait Printable { fn print(&self);}trait Scannable { fn scan(&self);}trait Faxable { fn fax(&self);}struct SimplePrinter;struct OfficeMachine;impl Printable for SimplePrinter { fn print(&self) { println!("Printing"); }}impl Printable for OfficeMachine { fn print(&self) { println!("Printing"); }}impl Scannable for OfficeMachine { fn scan(&self) { println!("Scanning"); }}impl Faxable for OfficeMachine { fn fax(&self) { println!("Faxing"); }}Why this follows ISP:
- Each interface represents a single capability
- Devices implement only the interfaces they support
- No empty implementations or exceptions
- Type system prevents calling unsupported methods
- Easy to add new capabilities without affecting existing devices
Benefits of Following ISP
Section titled “Benefits of Following ISP”Key Takeaways
Section titled “Key Takeaways”Remember: The Interface Segregation Principle ensures that classes only depend on methods they actually use, leading to cleaner and more maintainable code! 🎯