While reading Dive Into Design Patterns by Alexander Shvets, I stumbled across the following statement in the section "Favor Composition Over Inheritance":
Trying to reuse code through inheritance can lead to creating parallel inheritance hierarchies
According to this site the definition of parallel inheritance is the situation in which subclassing a class requires creating yet another subclass elsewhere. I'm interested in knowing what would be this kind of scenario, where we'd have to subclass all over the place, and further more the why of it: why would we have to create the subclass elsewhere? Does the need arise from the context and the problem we are trying to solve, or is it induced by the structure of the (at least) two class hierarchies and composition between them? While here is an attempt to give a mathematical definition for the parallel inheritance, the need for the implication is not clear to me.
CodePudding user response:
I understand this like that. Imagine you have
public abstract class CarBase
{
// all cars run on liquid fuel, right? This is 1955
public decimal FuelVolume { get; set; }
}
Then you inherit this and create your PUTruck
, SportsCar
, Sedan
etc
Suddenly, this is 2022 and you have Electric car. You will probably do
public abstract class ElectricCarBase : CarBase
{
public decimal ChargeVolume { get; set; }
}
^^ this will come with all the nastiness of unused and unneeded properties, bunch of noise, like Antifreeze and fuel lines. And you endup in parallel inheritance. You will need to create all sort of adapters to support all this..
Enter "Composition Over Inheritance"
public abstract class CarBase
{
public List<IFuelProvider> FuelSources { get; set; }
}
public interface IFuelProvider
{
public FuelType TypeOfFuel { get; set; }
public string MeasureUnit { get; set; }
public int FuelUnits { get; set; }
}
Now, you can support Gas, Electric or Hybrid
This is my understanding. Welcome to disagree
CodePudding user response:
When it comes to inheritance, it seems we can always take examples from the Animal Kingdom. So we have a class hierarchy of Animal
like this.
interface Animal {
void eat(Food someFood);
}
But every Animal
has its own special Food
. So when we subclass Animal
with Dog
we need to subclass Food
with DogFood
and when we subclass Animal
with Cat
we need to subclass Food
with CatFood
and so on.
Parallel hierarchies can occur naturally in a problem domain, in which case it may be sensible to model them the same way in code. But parallel hierarchies can also occur artificially in a solution domain, and that verbosity may be undesirable.
On StackOverflow, the syntactic question that often arises from this scenario is, how do I make sure my Animal doesn't eat the wrong Food?