I would appreciate some clarification on how to properly implement ‘Composition over Inheritance’. I think I have a grasp on the theory but in practice I struggle to understand how it doesn’t lead to code duplication.
I have the following example (it’s java, sorry):
Suppose we have an abstract animal class:
abstract class Animal {
protected void eat() {
// Common eating implementation
}
protected void sleep() {
// Common sleeping implementation
}
}
And we want to build both flying and swimming Animals. I understand that the best way to do this so that we follow LSP is with interfaces for each:
interface Flyer {
void fly();
}
interface Swimmer {
void swim();
}
So then we would have
class Salmon extends Animal implements Swimmer {
@Override
public void swim() {
// Swim implementation
}
}
class Sparrow extends Animal implements Flyer {
@Override
public void fly() {
// Fly implementation
}
}
But then we get a new requirement for a Magpie that flies the same way as a sparrow. We would create the class, not to different from a Sparrow:
class Magpie implements Animal implements Flyer {
@Override
public void fly() {
// Same exact fly implementation as Sparrow.fly
}
}
Imagine for the purpose of this exercise, that the fly implementation is very complex with db integration, logging, etc. – this leads to a load of duplicated code and if we add more birds or fishes, we’d need to duplicate the code even further.
There was also an idea of having an abstract class for the same type of flyers like
abstract class FlyingBird extends Animal implements Flyer
and have the common implementation there but what if we need to create a few of these and there’s an animal that needs to extend two of them? It’s a slippery slope…
Is there any way to avoid this? Or am I missing the mark somewhere?
zeldinho is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.