In a nutshell, you should define an interface when you need the ability to swap out an implementation defined bymap that interface (i.e. capability) to one or more implementations.
What does that phrase mean?
As an example, if you're unit testing and need to substitutepass a stub or mock forinto a constructor parameterclass for testing purposes, then that constructor parameter should be defined as an interface so that you can pass an object that appropriately "simulates" the correct behavior.
This is also the basis for the Dependency Inversion principle; instead of a class taking concrete dependencies on other classes and instantiating them directly (thereby creating tight coupling), the class implements dependencies by allowing conforming objects to be passed into the constructor via interfaces.
In your List
example, it's not a given that you need access to the List's entire set of capabilities. If you simply need to iterate over the list, it is sufficient to pass the list as an IEnumerable
, and you're exercising the Liskov Substitution Principle by doing so. You don't have to couple yourself to the entire List
class.