At the request of exizt, I'm expanding my comment to a longer answer.
The biggest mistake that people make is believing that interfaces are simply empty abstract classes. An interface is a way for a programmer to say, "I don't care what you give me, as long as it follows this convention."
The .NET library serves as a wonderful example. For example, when you write a function that accepts an IEnumerable<T>
, what you are saying is, "I don't care how you are storing your data. I just want to know that I can use a foreach
loop.
This leads to some very flexible code. Suddenly in order to be integrated, all you need to do is play by the rules of the existing interfaces. If implementing the interface is difficult or confusing, then maybe that is a hint that you are trying to shove a square peg in a round hole.
But then the question comes up: "What about code reuse? My CS professors told me that inheritance was the solution to all code reuse problems and that inheritance allows you to write once and use everywhere and it would cure menangitis in the process of rescuing orphans from the rising seas and there would be no more tears and on and on etc. etc. etc."
Using inheritance just because you like the sound of the words "code reuse" is a pretty bad idea. The code styling guide by Google makes this point fairly concisely:
Composition is often more appropriate than inheritance. ... [B]ecause
the code implementing a sub-class is spread between the base and the
sub-class, it can be more difficult to understand an implementation.
The sub-class cannot override functions that are not virtual, so the
sub-class cannot change implementation.
To illustrate why inheritance is not always the answer, I'm going to use a class called MySpecialFileWriter†. A person who blindly believes that inheritance is the solution to all problems would argue that you should try to inherit from FileStream
, lest you duplicate FileStream
's code. Smart people recognize that this is stupid. You should just have a FileStream
object in your class (either as a local or member variable) and use its functionality.
The FileStream
example may seem contrived, but it's not. If you have two classes that both implement the same interface in the exact same way, then you should have a third class that encapsulates whatever operation is duplicated. Your goal should be to write classes that are self-contained reusable blocks that can be put together like legos.
This doesn't mean that inheritance should be avoided at all costs. There are many points to consider, and most will be covered by researching the question, "Composition vs. Inheritance." Our very own Stack Overflow has a few good answers on the subject.
At the end of the day, your coworker's sentiments lack the depth or understanding necessary to make an informed decision. Research the subject and figure it out for yourself.
† When illustrating inheritance, everyone uses animals. That is useless. In 11 years of development, I've never written a class named Cat
, so I'm not going to use it as an example.
alligator
's implementation ofeat
differs, of course, in that it acceptscat
anddog
as parameters.is a
and interfaces areacts like
oris
. So a dogis a
mammal andacts like
an eater. This would tell us that mammal should be a class and eater should be an interface. It has always been a very helpful guide. Sidenote: An example ofis
would beThe cake is eatable
orThe book is writable
.