Interface Segregation Principle (ISP)
What is the Interface Segregation Principle?β
You: Hey Shubh, can you explain the Interface Segregation Principle to me?
Shubh: Sure! The Interface Segregation Principle (ISP) is one of the SOLID principles of object-oriented design. It suggests that no client should be forced to implement interfaces they don't use. Instead of having a large, general-purpose interface, it's better to have multiple smaller, more specific interfaces.
Example: Violation of ISP (Bad Approach)β
Let's look at an example where the Interface Segregation Principle is violated:
public interface Employee {
void washDishes();
void cookFood();
void serveFood();
}
public class Chef implements Employee {
@Override
public void washDishes() {
System.out.println("Chef cannot wash dishes");
}
@Override
public void cookFood() {
System.out.println("Chef is cooking the food");
}
@Override
public void serveFood() {
System.out.println("Chef cannot serve the food");
}
}
public class DishWasher implements Employee {
@Override
public void washDishes() {
System.out.println("Dishwasher is washing the dishes");
}
@Override
public void cookFood() {
System.out.println("Dishwasher cannot cook food");
}
@Override
public void serveFood() {
System.out.println("Dishwasher cannot serve food");
}
}
public class Waiter implements Employee {
@Override
public void washDishes() {
System.out.println("Waiter cannot wash dishes");
}
@Override
public void cookFood() {
System.out.println("Waiter cannot cook food");
}
@Override
public void serveFood() {
System.out.println("Waiter is serving the food");
}
}
public class Main {
public static void main(String[] args) {
Employee emp = new Chef();
emp.cookFood();
emp.serveFood();
emp.washDishes();
}
}
You: I see that the classes Chef
, DishWasher
, and Waiter
all implement the Employee
interface. What's wrong with this approach?
Shubh: The problem here is that the Employee
interface has methods that are not relevant to all types of employees. For example, a Chef
doesn't wash dishes or serve food, but because of this interface, the Chef
class must implement these methods. This approach forces classes to implement methods they don't need, leading to bloated and inefficient code.
A Better Approach: Applying the Interface Segregation Principleβ
To adhere to ISP, we should create several smaller, more specific interfaces rather than one large interface with many methods. This way, classes only need to implement the methods that are relevant to them.
You: How would we do that?
Shubh: Letβs refactor the code by breaking down the Employee
interface into more specific interfaces:
public interface ChefInterface {
void cookFood();
}
public class Chef implements ChefInterface {
@Override
public void cookFood() {
System.out.println("Chef is cooking the food");
}
}
public interface DishWasherInterface {
void washDishes();
}
public class DishWasher implements DishWasherInterface {
@Override
public void washDishes() {
System.out.println("Dishwasher is washing the dishes");
}
}
public interface WaiterInterface {
void serveFood();
}
public class Waiter implements WaiterInterface {
@Override
public void serveFood() {
System.out.println("Waiter is serving the food");
}
}
public class Main {
public static void main(String[] args) {
ChefInterface chef = new Chef();
chef.cookFood();
WaiterInterface waiter = new Waiter();
waiter.serveFood();
DishWasherInterface dishWasher = new DishWasher();
dishWasher.washDishes();
}
}
You: Now each class only implements the interface that defines the methods it actually uses. This seems much cleaner.
Shubh: Exactly! By breaking down the Employee
interface into smaller, more specific interfaces, we ensure that each class only deals with methods relevant to its role. This adheres to the Interface Segregation Principle, resulting in cleaner, more maintainable, and efficient code.