Interface is used to provide the specification or the abstraction of the functionality .In other words it just defines the signature of the methods without any implementation details.Implementing classes are required to implement all of the methods declared by an interface.
So if an interface contains five methods then any class which is implementing that interface will be required to implement all of the five methods.
Interface Segregation Principle states that Client should not be forced to implement the methods which it don’t need.
Lets understand this with an example
Suppose we have an interface which is contains the methods supposed to send email.
interface IEmail { bool SendMail(); string EmailAddress { get; set; } }
So any class which need to send an email will implement this interface and will provide the implementation of all the contained methods.
class User:IEmail { private string emailAddress; public bool SendMail() { //send email functionality return true; } public string EmailAddress { get { return emailAddress; } set { emailAddress = value; } } }
Now suppose we need to implement the logging functionality as well in our class when an email is sent.So we are tempted to modify the existing interface and introduce a new method to do the logging
interface IEmail { bool SendMail(); string EmailAddress { get; set; } bool LogToFile(); }
The above example though looks fine but has few problems
- If the existing interface is already implemented by lot of classes then if we introduce a new method to do the logging then our existing code will break as the existing classes do not implement the logging method
- If one of the clients of the above class needs to just send an email without logging as it already implements the logging functionality then the client has no option but to implement the logging method as well since it is one of the methods of the interface.
The interface IEmail defined above is an example of fat interface.Fat interface is an interface which contains lots of methods and many of the methods are not required by most of the clients.
The solution to the above problem is the Interface Segregation Principle Now instead of having a single interface declaring both the email and logging methods we define two separate interfaces
Interface containing the email functionality
interface IEmail { bool SendMail(); string EmailAddress { get; set; } }
Interface containing the logging functionality
interface ILog { bool LogToFile(); }
The consequence of the above segregation of the methods into different interfaces is
- Our existing classes are not required to be changed to include the new interface methods
- The consumers of the email class are not forced to implement the logging method as
well.If the consumer of our class wants to log some information then it can implement the logging interface.
So according to this principle there should be many interfaces declaring specific functionalities instead of a single interface declaring lot of unrelated functionality.Such interfaces which contains only specific functionality are called role interfaces.
If we have a single interface which contains lots of unrelated methods then if we make only a small change in that interface then not only will all the existing classes will need to be changed but also they will be required to be tested again which can be a significant effort.
In contrast if the interface contains only small number of related methods then this means that only specific classes will require to be changed.So ISP or Interface segregation principle helps develop applications which are easier to maintain and refactor.
This is another example of fat interface
Following an interface which defines a bunch of methods
interface IEmployee { public decimal getSalary(int empId); public string getDepartment(int empId); public bool hrHire(string details); public bool adminCheckLocation(string details); public bool itManagerInterview(string details); }
The above method contains methods which is required by employees in the different departments.This interface not only contains the common methods getSalary() and getDepartment() but also other methods.Methods such as hrHire is required by employee in HR department while the method adminCheckLocation is required by the employee in admin department.
This is an example of a fat interface.This is not a very good design and will create the following problems
If a class requires functionality for only one department ,such as HR he is expected to implement all the methods whether he requires them or not.
If you make even a small change in the fat interface there is a good probability of breaking the entire application ,if there is a bug in the functionality.
Solution is to segregate the functionality in different interfaces and then the different classes can implement only the specific interfaces.So if we implement interface segregation principle here then our interface structure will be like
interface IEmployee { public decimal getSalary(int empId); public string getDepartment(int empId); } interface IEmployee:IHR { public bool hrHire(string details); } inteface IAdmin:IEmployee { public bool adminCheckLocation(string details); } interface IManager::IEmployee { public bool itManagerInterview(string details); }
This design provides following benefits:
user will instantiate class implementing a specific interface rather then a single interface containing all the functioanlity.
there is less chance of breaking application if there is an error in specific interface.
Leave a Reply