The SOLID Principles are the design principles that enable us to manage several software design problems. These principles provide us with ways to move from tightly coupled code to loosely coupled and encapsulated real business needs properly. Also readable, adaptable, and scalable code.
The SOLID Principles guide developers as they write readable, adaptable, and scalable code or design
an application.
The SOLID Principles can be
applied to any OOP program.
The SOLID Principles were
developed by computer science instructor and author Robert C. Martin. Now,
SOLID principles have also been adopted in both agile development and adaptive
software development.
The 5 principles
of SOLID are:
1. Single Responsibility Principle (SRP)
2. Open Closed Principle (OCP)
3. Liskov Substitution Principle (LSP)
4. Interface Segregation Principle (ISP)
5. Dependency Inversion Principle (DIP)
SOLID Principle: (4) Interface Segregation Principle (ISP)
The Interface Segregation Principle (ISP) is one of the SOLID principles of object-oriented design.
By Robert C.
Martin -
Interface Segregation Principle (ISP)
states that clients should not be forced to implement interfaces they do not
use.
Interface Segregation Principle (ISP)
splits interfaces that are very large into smaller and more specific ones so
that clients will only have to know about the methods they actually need.
Implementation: Interface Segregation Principle (ISP) C# Live
Example:
Let us consider an example to Explain
the Interface Segregation Principle (ISP) in C#, suppose we have an IWorker
interface that defines methods for various types of work, such as Work, Eat,
and Sleep.
First, define an
interface IWorker interface that has three methods Work (), Eat (), and Sleep ():
//IWorker
interface
public interface IWorker
{
void
Work();
void
Eat();
void
Sleep();
}
Now, imagine we have two classes, HumanWorker and RobotWorker, that implement to IWorker interface.
Second, define a HumanWorker class that implements the IWorker interface:
//HumanWorker
class that implements to IWorker interface
public class HumanWorker: IWorker
{
public void Work() { /*...*/ }
public void Eat() { /*...*/ }
public void Sleep() { /*...*/ }
}
Third, define a RobotWorker class that also implements the IWorker interface. The Robot cannot Eat and Sleep but is forced to Eat () and Sleep () methods (violates the ISP):
//RobotWorker
class that implements to IWorker interface
public class RobotWorker : IWorker
{
public void Work() { /*...*/ }
/* Not needed for robots worker because they not eat food.
*/
public void Eat() { /*...*/ }
/* Not needed for robots worker because they not eat sleep.
*/
public void Sleep() { /*...*/ }
}
Here IWorker interface violates the Interface Segregation Principle (ISP) and it's forcing the RobotWorker class to implement the Eat () and Sleep () methods that are irrelevant to the robot’s class.
To fix the issue of violating the Interface Segregation Principle (ISP), we need to break down the large interface into smaller ones.
Let's break down the IWorker interface into smaller, See the C# code,
//IWorkable
interface
public interface IWorkable
{
void
Work();
}
//IEatable
interface
public interface IEatable
{
void
Eat();
}
//ISleepable
interface
public interface ISleepable
{
void
Sleep();
}
Now, the HumanWorker class will
implement all three interfaces (IWorkable, IEatable, ISleepable), while
the RobotWorker class only needs to implement the (IWorkable)
interface. See the C# code,
//HumanWorker
class and inherited to IWorkable, IEatable, ISleepable interfaces
public class HumanWorker: IWorkable, IEatable, ISleepable
{
public void Work() { /*...*/ }
public void Eat() { /*...*/ }
public void Sleep() { /*...*/ }
}
//RobotWorker class and inherited only IWorkable interface
public class RobotWorker: IWorkable
{
public void Work() { /*...*/ }
}
Now we have ensured that clients only
implement the methods they actually need.
Put it all together to follow the Interface Segregation Principle (ISP) in C#,
namespace ISP;
public interface IWorkable
{
void
Work();
}
public interface IEatable
{
void
Eat();
}
public interface ISleepable
{
void
Sleep();
}
public class HumanWorker: IWorkable, IEatable, ISleepable
{
public void Work () {/*...*/}
public void Eat () {/*...*/}
public void Sleep () {/*...*/}
}
public class RobotWorker: IWorkable
{
public void Work () {/*...*/}
}
public class Program
{
public static void Main(string[]
args)
{
// HumanWorker
var
homenWorker = new HumanWorker();
homenWorker.Work();
homenWorker.Eat();
homenWorker.Sleep();
// RobotWorker
var
robotWorker = new RobotWorker();
robotWorker.Work();
}
}
What Are the Advantages of Interface Segregation Principle (ISP) in C#?
1. Reduced Dependencies: Breaking interfaces into smaller, more
specific ones reduces the number of methods each class is required to
implement.
2. Improved Code Maintainability: With smaller, more focused interfaces, it
becomes easier to understand and maintain the code.
3. Flexibility and Extensibility: Classes developed by the ISP are more flexible
and extensible.
4. Easier Testing: Smaller interfaces make it easier to create
and perform unit tests.
5. Avoiding Fat Interfaces: ISP prevents the creation of "fat
interfaces". Fat interfaces violate the single responsibility principle.
Breaking down interfaces helps avoid this issue.
6. Clearer Intent: Specific interfaces convey the intent and
responsibilities of implementing classes more clearly. This makes the codebase
more self-documenting and easier to understand.
What Are the Disadvantages of Interface Segregation Principle (ISP) in C#?
1. Increased Number of Interfaces: More interfaces will create the challenge
to manage and understand the relationships between various interfaces.
2. Increased Development Time: Creating and managing a large number of
small interfaces might increase the time and effort required during the
development phase.
How to use the Interface Segregation Principle effectively in C#?
1. Identify Client Needs: To identify the client
needs and split fat interfaces into smaller ones.
2. Refactor Existing Interfaces
3. Avoid Fat Interfaces
4. Apply Dependency Injection