If you are comfortable with the single responsibility principle, the interface segregation principle will make perfect sense. It’s the same thing, only for interfaces:
An interface should describe one set of behaviors.
You can run into the same trouble with interfaces as with classes. You need to add a new capability to an existing interface, rather than creating a new one. Now all implementing classes have one more thing they have to account for. 😐
Keeping interfaces small and to the point decreases coupling. Coupling refers to how closely connected two pieces of software are. The more an interface defines, the more an implementing class needs to do as well. That makes that class less reusable.
Because of Python's famous duck typing feature, interfaces are not used as extensively as in other programming languages. If an object walks like a duck and swims like a duck, then Python is happy to treat it as a duck, even if it is a swan!
But you’ll often find yourself in a situation where you want two or more classes to act as alternatives to one another, even if they don’t implement any explicit interface. In this case, the interface segregation principle still applies! It tells you not to expose unnecessary methods in these classes. Because if you do, you have to add an equivalent method to all of its alternatives!
How Do We Apply the Interface Segregation Principle to Our Code?
Due to popular demand, audiences around the world want to watch our exciting card game on their televisions and streamed over the internet. Let’s make it happen!
We’re going to need three different sorts of view:
PlayerView: the players interact with this (renamed from View)
Are we still using the MVC design pattern? Or something like MVVVC because of the extra views?
It’s still MVC! Our view contains several components, just like our model contains the PlayingCard, Deck, and Player components.
Follow with your own copy of the code as we do this together! First, download the following file: card-game-p3-ch5-d1.py. Then join me in the screencast below:
Our solution works, but some of the code seemed rather pointless. Some of the methods - such as
BroadcastView.prompt_for_flip_cards - had to be carefully implemented so they wouldn't affect the game.
These methods should never need to be called or implemented. This is a clear sign that we’re violating the interface segregation principle!
What can we do instead?
Ultimately we want BroadcastView and InternetStreamingView to contain only the following methods:
We then have to rewrite the code so that view objects aren’t expected to implement any other methods, unless it’s PlayerView.
Try it yourself—reverting your edits from the previous video if necessary— and then take a look at one potential solution, in the video below.
We’ve successfully written a collection of alternative view objects that aren’t bloated by unnecessary methods, despite the extra functionality that needs to be preserved in PlayerView.
Interface segregation is the single responsibility principle for interfaces.
It’s easy to violate the principle. The temptation is to add a new method to an existing interface, since it’s already doing something.
When in doubt, it's better to have two interfaces with few methods to implement, rather than a single interface with too many responsibilities.
In the next chapter, we will look at ensuring that our low-level implementations don't drive higher-level classes' implementations!