SOLID: Interface Segregation Principle
Interface Segregation Principle (ISP) is the fourth principle of SOLID principles. It can be used in conjunction with LSP.
Interface Segregation Principle (ISP) states that:
Now, you may wondering, who is the client and what and whose methods it is talking about?
Here, a client is a code that calls the methods of a class with an instance of the interface. For example, a class implements an interface that contains 10 methods. Now, you create an object of that class with a variable of that interface and call only 5 methods for the functionality you wanted and never call the other 5 methods. So, this means that the interface contains more methods that are not used by all client codes. It is called a fat interface. ISP suggests segregating that interface into two or more interfaces so that a class can implement the specific interface that it requires.
Let's use the following interface to learn ISP in detail:
public interface IStudentRepository
{
void AddStudent(Student std);
void EditStudent(Student std);
void DeleteStudent(Student std);
void AddCourse(Course cs);
void EditCourse(Course cs);
void DeleteCourse(Course cs);
bool SubscribeCourse(Course cs);
bool UnSubscribeCourse(Course cs);
IList<Student> GetAllStudents();
IList<Student> GetAllStudents(Course cs);
IList<Course> GetAllCourse();
IList<Course> GetAllCourses(Student std);
}
public class StudentRepository : IStudentRepository
{
public void AddCourse(Course cs)
{
//implementation code removed for better clarity
}
public void AddStudent(Student std)
{
//implementation code removed for better clarity
}
public void DeleteCourse(Course cs)
{
//implementation code removed for better clarity
}
public void DeleteStudent(Student std)
{
//implementation code removed for better clarity
}
public void EditCourse(Course cs)
{
//implementation code removed for better clarity
}
public void EditStudent(Student std)
{
//implementation code removed for better clarity
}
public IList<Course> GetAllCourse()
{
//implementation code removed for better clarity
}
public IList<Course> GetAllCourses(Student std)
{
//implementation code removed for better clarity
}
public IList<Student> GetAllStudents()
{
//implementation code removed for better clarity
}
public IList<Student> GetAllStudents(Course cs)
{
//implementation code removed for better clarity
}
public bool SubscribeCourse(Course cs)
{
//implementation code removed for better clarity
}
public bool UnSubscribeCourse(Course cs)
{
//implementation code removed for better clarity
}
}
The above IStudentRepository
interface contains 12 methods for different purposes. The StudentRepository
class implements the IStudentRepository
interface.
Now, after some time, you observe that not all instances of the StudentRepository
class call all the methods. Sometimes it calls methods that perform student-related tasks or sometimes calls course-related methods. Also, the StudentRepository
does not follow the single responsibility principle because you may need to edit its code if student related as well as course-related business logic changes.
To apply ISP to the above problem, we can split our large interface IStudentRepository
and create another interface ICourseRepository
with all course-related methods, as shown below.
public interface IStudentRepository
{
void AddStudent(Student std);
void EditStudent(Student std);
void DeleteStudent(Student std);
bool SubscribeCourse(Course cs);
bool UnSubscribeCourse(Course cs);
IList<Student> GetAllStudents();
IList<Student> GetAllStudents(Course cs);
}
public interface ICourseRepository
{
void AddCourse(Course cs);
void EditCourse(Course cs);
void DeleteCourse(Course cs);
IList<Course> GetAllCourse();
IList<Course> GetAllCourses(Student std);
}
Now, we can create two concrete classes that implement the above two interfaces. This will automatically support SRP and increase cohesion.
ISP is not specific to interfaces only but it can be used with abstract classes or any class that provides some services to the client code.
ISP helps in implementing Liskov Substitution Principle, increasing cohesion that in turn supports the Single Responsibility Principle.
The following code smells detects ISP violation:
- When you have large interfaces.
-
When you implement an interface in a concrete class where some methods do not have any implementation code or throw
NotImplementedException
. - When you call only a small set of methods of a larger interface.
The solution to ISP violations:
- Split large interfaces into smaller ones.
- inherit multiple small interfaces if required.
- Use the adapter design pattern for the third-party large interface so that your code can work with the adapter.