This principle demands that clients should not be forced to depend on interfaces they do not use. An entity (class, service, …) is client of an interface, if it uses a class that implements the interface.
Applying this principle is fairly easy. A similar methodology to the one already used in the Single Responsibility Principle (SRP) must be applied. When developing services, it is often necessary to have classes with multiple responsibilities. The Interface Segregation Principle (ISP) permits to limit class coupling between the different classes in this case.
In the following example the class BusinessObject has multiple responsibilities (implements multiple functional groups) like creation, update, validation and deletion.
Please note the usage of the interface IBusinessObject instead of the class BusinessObject. This approach is called Interface-Based Programming. It allows programming against interfaces instead of concrete classes. Thus, all classes implementing the interfaces required by those functions can be passed as parameters to them. This already provides some degree of independency, but there are still flaws in this class design.
Each client only uses some aspects of the defined interface:
- The ValidationManager class only uses methods concerning validation
- The PersistManager class only uses methods concerning persistence
Modifications of methods concerning the validation imply modifications to the whole interface IBusinessObject and indirectly to the PersistManager class. Even though the PersistManager class does not even use those methods !!
We need to find a solution to achieve that different clients only depend on functionality and access methods that they really use.
The first step consists of regrouping all methods that belong to the same functional group in specialized interfaces. Similar to what we already did for the Single Responsibility Principle (SRP) only this time with specialized interfaces as output.
The interface IBusinessObject is separated into two more specialized interfaces IPersistable and IValidatable. It then inherits from those newly created interfaces.
Now it is possible to use the different functionalities Persistence and Validation separately as well as using both at the same time. Modifications can be done without any impact between those two functional groups, they evolve independently from each other.
The next step is to replace the current usage of the interface IBusinessObject with the specialized interfaces IPersistable and IValidatable where applicable.
To conclude I would like to underline that in terms of decoupling multiple specialized interfaces are better that one big global interface that contains everything. This approach can also be applied to abstract classes since they might somewhat be considered as interfaces.
5 comments:
I like your examples, however I need to point out that your last point is the exact reason to use interfaces: you can't inherit from multiple abstract classes.
I am happy that you like my examples !
But I think there is some kind of misunderstanding, since I never meant to say that you could inherit from multiples abstract classes, which is just not possible (luckily !) in C# as you correctly pointed out.
I just wanted to explain that you could also use abstract classes to define specialized interfaces. But I forgot to add that you would somewhat be limited if you used this approach.
I also tend to always use interfaces which are the best choice in this case and I recommend using them instead of abstract classes.
Thanks for this clarification anyways !
the example given as helpful..thankyou
Good example of "fat" interface
Hi,
Could you please explain what do you mean by "Modifications of methods concerning the validation imply modifications to the whole interface IBusinessObject and indirectly to the PersistManager class. Even though the PersistManager class does not even use those methods !!"
Maybe provide an example. This is for me the more complicated aspect of the Interface Segregation Principle.
Post a Comment