GetNoticed IT#7: S-O-L-Interface Segregation Principle-D

Hello there!
Today the last ‘episode’ of my SOLID series. The only only that is left for today is Interface Segregation Principle.

Clients should not be forced to depend upon interfaces that they do not use. [see here, page 5]

In practice, this means that implementing an interface should force a class to implement only those features that the class actually uses. Nice example is give by Piotr Zieliński here after But let me add a pinch of my own imagination here. Let’s think about workers. A worker is someone who does some work and gets paid for it.

Nice and clear. No problems. But we live in 21st century, a brave new world! We can use robots to do some work. But the problem is that a robot doesn’t need to get paid. So, you either throw an exception or leave implementation of this method blank. But that’s not a right approach.

Chris Klug even brought up an example of MembershipProvider (which is an abstract class not an interface to be precise, but that depicts a problem with complex interfaces in a pretty good way.) in where it was almost impossible to implement all features!

So, the  general rule is smaller but more rather than complex and few. Benefits we get from following that approach are multiple. First of all, if we break code to smaller pieces it is easier to get it, it keeps the code clean. Secondly, you don’t need to worry about something you don’t need, you don’t have to write empty methods or build properties your class will never ever use.
Let’s update and expand our example little bit to follow the principle. I’m going to split IWorker interface into three separate interfaces: ICanWork, IHuman, and IRobot. Additionaly IRobot will get PowerConsumption property.

That seems to be written better than the initial code, doesn’t it? But now, our factory needs to keep track of how a robot is performing. In order to do that we need to log all the work it is doing and count its total power consumption. That leads to a problem. First thought is to write a new class and inject a RoboWorker. But that would result in the Dependency Inversion Principle broken. We could do that or inject RoboWorker twice: first as IRobot and second as ICanWork; or else inject it once and then use “ICanWork as IRobot” statement.

But that is terrible, terrible idea as there is no way to be sure that object you will inject into PowerCounter implements IRobot interface. So, don’t even think about it as there is a better way – some call it super-interface. You simply create another interface which inherit all required interfaces and make our RoboWorker class implement that interface instead of two separated. In our case it’s going to be ICanWork and IRobot.

[edited 24-04-17]
I have been thinking about that solution given above and I couldn’t get rid of this feeling that it’s not the best way. And in fact it isn’t. First and foremost, in our example we had first written our class RoboWorker so it implemented two interfaces and then we replaced them with one interface that combines the former two, and that is violation of Open/Closed Principle – once a class is done it’s done. So better solution for PowerCounter needed here – generics to the rescue. PowerCounter will take generic-type parameter T which implements both interfaces implemented by RoboWorker.

In the above code PowerCounter class has one T type field which holds reference to an object supplied in the constructor. Usage of this would be as follows:

Now, it is nice and clean.

That’s it. Seems that I have now covered all SOLID principles. Hope you enjoyed!
Cheers, Michal

896isp.pdf by Robert Martin

Me about SOLID:
Single Responsiblity Principle
Open/Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inversion Principle