To become a senior among millions of programmers!
Introduction
This is the fourth article in the series “SOLID for young hard-coded youth.” In this article, I will talk about the Interface Segregation Principle — The principle of separating interfaces.
- Single Responsibility Principle
- Open / Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
Instead of using a large interface, we should split into many small interfaces, with many specific purposes
Explain the principle
Before explaining the principle, I repeat the interface concept a bit for you to lose the basics.
The interface is an empty class containing the declaration of the method name without declaring properties or anything else, and these methods are also empty. Therefore, any class that uses the interface class must define the methods declared in the interface class.
To design a flexible, easy-to-change system, the system’s modules should communicate with each other through the interface. Each module will call another module’s function through the interface, regardless of the implementation below. As mentioned above, since the interface only contains an empty method declaration, when a class implements an interface, it must implement all the methods declared in that interface.
This is equivalent to the fact that if we create a large interface (more than 100 methods, for example), each class will have to implement all 100 methods, including the methods that are never used. If we apply the ISP, we will divide this interface into many small interfaces; the classes need to implement the interfaces with the functions they need, no need to implement redundant functions.
Example
This is the easiest principle in SOLID to understand; you only need to read the code a little to understand it immediately! Suppose we want to write a program to show the properties of animals. Any animal can eat, drink, sleep; we design the interface IAnimal as follows:
public interface IAnimal {
void Eat();
void Drink();
void Sleep();
}
public class Dog : IAnimal {
public void Eat () {}
public void Drink () {}
public void Sleep () {}
}
public class Cat : IAnimal {
public void Eat () {}
public void Drink () {}
public void Sleep () {}
}
When we want to add some new animals and features, we have to add methods to the interface such as swimming, flying, hunting, … This causes the interface to swell. When an animal inherits an interface, it must also implement functions that are not used.
In practice, too, when we need to add new functions, we often add methods to the interface, causing the interface to grow larger. When adding methods to the IAnimal interface, the old classes like Dog and Cat have to implement new methods, so it takes time. The solution in this situation is to separate the interface IAnimal into small interfaces as follows:
To properly split a large interface into small interfaces, you should review the first article in the series on the Single Responsibility Principle. However, sometimes the separation of multiple interfaces can increase the number of interfaces, increase the number of classes, and consider the benefits before applying.
Conclusion
Applying the ISP principle will make the system more flexible while minimizing redundant code (due to implementing unnecessary features). However, in practice, there are still many cases of force majeure that we have to create a large interface. For example: In an ASP.NET application, if you want to implement the login/authorization function for the user, you must implement the interface MembershipProvider. This interface is quite big with more than 27 methods (now there are more).
Perhaps Microsoft's purpose when designing this interface is to cover all the required login/authorization functionality. However, due to this large interface, if we want to do simple decentralization, then implementing these 27 methods is completely time consuming and unnecessary.
References
https://www.codeproject.com/Tips/766045/Interface-Segregation-Principle-ISP-of-SOLID-in-Cs