Interface Segregation Principle of SOLID | ISP
SOLID Principles are one of the mandatory questions in each and every interview. This is the 5th part of the SOLID Design Principle. In this part, we will walk through the 4th SOLID Design Principle i.e Interface Segregation Principle (ISP) in detail with live real examples.
Please read the previous parts here over the below links:
Single Responsibility Principle
Introduction
In the SOLID acronym, the fourth letter "I" represents the "Interface Segregation Principle". Segregation means keeping things separated, and the Interface Segregation Principle is about separating the interfaces. This principle is related to the Single Responsibility Principle in that even interfaces also should have a single purpose.
Using interfaces is one of the best ways to allow the extensibility and testability of the application. ISP is intended to keep a system decoupled so that it is easier to refactor, change, test and redeploy.
Interfaces should belong to clients, not to libraries or hierarchies. Application developers should favor thin and focused interfaces compared to "fat" interfaces that offer more functionality than a particular class or method needs.
Ideally, your thin interfaces should be cohesive, meaning they have groups of operations that logically belong together. This will prevent you from ending up with one-interface-per-method most of the time in real-world systems. Another benefit of smaller interfaces is that they are easier to implement fully, and therefore less likely to break the Liskov Substitution Principle by being only partially implemented.
In many OOPS languages like C#, interfaces can inherit from multiple other interfaces. So, if you need a larger interface in some parts of the application, but not in others, you can compose it from two or more other interfaces as well.
Interface Segregation Principle (ISP)
The Interface Segregation Principle is the fourth SOLID Design Principle. Segregation means keeping things separated, and the Interface Segregation Principle is about separating the interfaces.
The Interface Segregation Principle was first used and formulated by Robert C. Martin while consulting for Xerox to help them build the software for their new printer systems.
So in short the interfaces should also follow the first rule of SOLID i.e Single Responsibility Principle. Similar to the Single Responsibility Principle, the goal of the Interface Segregation Principle is to reduce the side effects and frequency of required changes by splitting the software into multiple, independent parts.
Definition of ISP
Interface Segregation Principle splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them.
According to Robert C. Martin:
Clients should not be forced to depend upon interfaces that they do not use.
In other words:
"Many client-specific interfaces are better than one general-purpose interface."
The Interface Segregation Principle states that no client should be forced to depend on methods that it does not use. So here this principle basically says two things:
a) No class should be forced to implement any method(s) of an interface they don’t use or are not related.
b) Instead of creating large or fat interfaces create multiple smaller interfaces so that the clients (class) should only think about the methods that are of interest to them (related).
Hence keep the interface as simple and small as possible. If required an interface can inherit from other interfaces to have the other behavior. On the other hand, the concrete class or client can also implement multiple interfaces as multiple interface inheritance are allowed.
Explanation
A client should never be forced to implement an interface that it doesn’t use, or clients should not be forced to depend on methods they do not use. This is only achievable if you define your interfaces so that they fit a specific client or task.
So larger interfaces should be split into smaller ones. By doing so, we can ensure that implementing classes only need to be concerned about the methods that are of interest to them. The code that violates ISP is also known as ‘Interface Pollution’.
An interface is implemented by the classes or clients. If the interface contains non-related methods then the client must have to implement those non-related or non required methods also whether they are required or not by the client or class.
And according to the Liskov Substitution Principle, the child class or derived class should not keep any base class or interface method non-implemented. So if you implemented an interface and you have to throw NotImplementedExceptions as you don't require those implementations you are probably doing something wrong and also violating both the Liskov Substitution Principle and Interface Segregation Principle.
When it comes to developing your own classes, think about the specific functionality needed and split that into different interfaces. This satisfies the ISP principle as classes that inherit the interfaces aren’t required to implement functionality they don’t need.
Interface Segregation Principle vs. Single Responsibility Principle
The goal of both the Interface Segregation Principle and Single Responsibility Principle is pretty much the same i.e ensuring small, focused, and highly cohesive software components.
The only difference is that the Single Responsibility Principle is concerned with classes, while the Interface Segregation Principle is concerned with interfaces.
In Object-Oriented Programming, we normally use an interface to be implemented by the classes, if our interface follows the ISP, the implementing class is automatically going to adhere to the SRP.
When applying the ISP to software development, we separate interfaces into their functional areas similar to the SRP. Where SRP is applied to classes and methods, ISP applies to interfaces.
Real Example of Interface Segregation Principles in the .Net Framework
The Interface Segregation Principle is used very effectively in the .NET Framework. One of the keys to making LINQ work is the IQueryable<T> interface and it is defined as:
As you can see, IQueryable<T> inherits from three other interfaces and these three separate interfaces have only required and related methods only. For example, IEnumerable<T> defines the enumerator over generic collections while IEnumerable over non-generic collections.
Similarly, some other examples of ISP like Array, String, DateTime, Int32, and Delegate are as below:
Example
interface IRepository
{
void Write(object data);
object Read();
}
public class DatabaseRepository : IRepository
{
public object Read()
{
//Logic to read data from the database
return new object();
}
public void Write(object data)
{
//Logic to write data into the Database
}
}
public class XMLRepository : IRepository
{
public object Read()
{
//Logic to read data from the XML
return new object();
}
public void Write(object data)
{
//Don't allow a user to write data to the XML Repository.
throw new NotImplementedException();
}
}
}
interface IReadOnlyRepository
{
object Read();
}
interface IWriteOnlyRepository
{
void Write(object data);
}
public class DatabaseRepository : IReadOnlyRepository, IWriteOnlyRepository
{
public object Read()
{
//Logic to read data from the database
return new object();
}
public void Write(object data)
{
//Logic to write data into the Database
}
}
public class XMLRepository : IReadOnlyRepository
{
public object Read()
{
//Logic to read data from the XML
return new object();
}
}
}
Recommended Articles
Static Class and Methods in C#
Constructor and Types of Constructors in C#
Dynamic Polymorphism C#
External Reference Links
Single Responsibility Principle
No comments:
Post a Comment
Please do not enter any HTML. JavaScript or spam link in the comment box.