Practical Examples of Interface Segregation Principle
Interface Segregation Principle (ISP)
Practical Examples
Example 1: Good Design
Here is a code snippet showing an interface that adheres to ISP by having smaller, client-specific interfaces:
- Java
- JavaScript
- Python
interface Printer {
void print(Document doc);
}
interface Scanner {
void scan(Document doc);
}
class MultiFunctionPrinter implements Printer, Scanner {
@Override
public void print(Document doc) {
System.out.println("Printing document");
}
@Override
public void scan(Document doc) {
System.out.println("Scanning document");
}
}
class SimplePrinter implements Printer {
@Override
public void print(Document doc) {
System.out.println("Printing document");
}
}
class Printer {
print(doc) {
console.log("Printing document");
}
}
class Scanner {
scan(doc) {
console.log("Scanning document");
}
}
class MultiFunctionPrinter extends Printer, Scanner {
print(doc) {
console.log("Printing document");
}
scan(doc) {
console.log("Scanning document");
}
}
class SimplePrinter extends Printer {
print(doc) {
console.log("Printing document");
}
}
class Printer:
def print(self, doc):
print("Printing document")
class Scanner:
def scan(self, doc):
print("Scanning document")
class MultiFunctionPrinter(Printer, Scanner):
def print(self, doc):
print("Printing document")
def scan(self, doc):
print("Scanning document")
class SimplePrinter(Printer):
def print(self, doc):
print("Printing document")
Example 2: Violation
Here is a code snippet where a single interface is overloaded with methods, violating ISP:
- Java
- JavaScript
- Python
interface Machine {
void print(Document doc);
void scan(Document doc);
void fax(Document doc);
}
class MultiFunctionPrinter implements Machine {
@Override
public void print(Document doc) {
System.out.println("Printing document");
}
@Override
public void scan(Document doc) {
System.out.println("Scanning document");
}
@Override
public void fax(Document doc) {
System.out.println("Faxing document");
}
}
class SimplePrinter implements Machine {
@Override
public void print(Document doc) {
System.out.println("Printing document");
}
@Override
public void scan(Document doc) {
// Not implemented
}
@Override
public void fax(Document doc) {
// Not implemented
}
}
class Machine {
print(doc) {
throw new Error('This method should be overridden')
}
scan(doc) {
throw new Error('This method should be overridden')
}
fax(doc) {
throw new Error('This method should be overridden')
}
}
class MultiFunctionPrinter extends Machine {
print(doc) {
console.log('Printing document')
}
scan(doc) {
console.log('Scanning document')
}
fax(doc) {
console.log('Faxing document')
}
}
class SimplePrinter extends Machine {
print(doc) {
console.log('Printing document')
}
scan(doc) {
// Not implemented
}
fax(doc) {
// Not implemented
}
}
class Machine:
def print(self, doc):
raise NotImplementedError("This method should be overridden")
def scan(self, doc):
raise NotImplementedError("This method should be overridden")
def fax(self, doc):
raise NotImplementedError("This method should be overridden")
class MultiFunctionPrinter(Machine):
def print(self, doc):
print("Printing document")
def scan(self, doc):
print("Scanning document")
def fax(self, doc):
print("Faxing document")
class SimplePrinter(Machine):
def print(self, doc):
print("Printing document")
def scan(self, doc):
# Not implemented
pass
def fax(self, doc):
# Not implemented
pass
Refactor Example 2
Refactor the violating example to split the interface into smaller, client-specific interfaces:
- Java
- JavaScript
- Python
interface Printer {
void print(Document doc);
}
interface Scanner {
void scan(Document doc);
}
interface Fax {
void fax(Document doc);
}
class MultiFunctionPrinter implements Printer, Scanner, Fax {
@Override
public void print(Document doc) {
System.out.println("Printing document");
}
@Override
public void scan(Document doc) {
System.out.println("Scanning document");
}
@Override
public void fax(Document doc) {
System.out.println("Faxing document");
}
}
class SimplePrinter implements Printer {
@Override
public void print(Document doc) {
System.out.println("Printing document");
}
}
class Printer {
print(doc) {
console.log("Printing document");
}
}
class Scanner {
scan(doc) {
console.log("Scanning document");
}
}
class Fax {
fax(doc) {
console.log("Faxing document");
}
}
class MultiFunctionPrinter extends Printer, Scanner, Fax {
print(doc) {
console.log("Printing document");
}
scan(doc) {
console.log("Scanning document");
}
fax(doc) {
console.log("Faxing document");
}
}
class SimplePrinter extends Printer {
print(doc) {
console.log("Printing document");
}
}
class Printer:
def print(self, doc):
print("Printing document")
class Scanner:
def scan(self, doc):
print("Scanning document")
class Fax:
def fax(self, doc):
print("Faxing document")
class MultiFunctionPrinter(Printer, Scanner, Fax):
def print(self, doc):
print("Printing document")
def scan(self, doc):
print("Scanning document")
def fax(self, doc):
print("Faxing document")
class SimplePrinter(Printer):
def print(self, doc):
print("Printing document")
By refactoring the large interface into smaller, client-specific interfaces, we adhere to the Interface Segregation Principle, leading to a more modular, maintainable, and flexible design.