Search code examples
oopinheritancedesign-patternslanguage-agnostic

How to Solve Parallel Inheritance Hierarchies when we try to reuse code through inheritance


Recently in a job interview, they ask me "how to solve Parallel Inheritance Hierarchies when we try to reuse code through inheritance". I thought on Aggregation or Composition, but i was a little confused on making an example based on that.

So I decided to leave it pending to deepen concepts later, but after investigating it did not end up forming a precise answer to that question, could someone explain me a solution or an example to this?


Solution

  • Parallel Inheritance Hierarchies makes many unnecessary classes and makes code very fragile and tightly coupled. For example, we have class Sportsman and its Goal's.

    public abstract class Sportsman
    {
        public string Name { get; set; }
    
        public abstract string ShowGoal();
    }
    

    and concrete class Footballer:

    public class Footballer : Sportsman
    {
        public override string ShowGoal()
        {
            return new FootballerGoal().Get();
        }
    }
    

    and Runner:

    public class Runner : Sportsman
    {
        public override string ShowGoal()
        {
            return new RunnerGoal().Get();
        }
    }
    

    Then we have their goals:

    public abstract class Goal
    {
        public abstract string Get();
    }
    

    and its concrete classes:

    public class FootballerGoal : Goal
    {
        public override string Get()
        {
            return "Score 1 goal";
        }
    }
    

    And runner goal:

     public class RunnerGoal : Goal
    {
        public override string Get()
        {
            return "Run 1 km";
        }
    }
    

    Now, it can be seen that if we add new type of sportsman, then we need add a new class to hierarchy of Goal.

    We can try to avoid of creation of that hierarchy tree by using dependency injection and extracting method to interface.

    At first, we create interface:

    public interface IGoal
    {
        string Visit(Sportsman sportsman);
    }
    

    and then just implement it:

    public class FootballerGoal : IGoal
    {
        public string Visit(Sportsman sportsman)
        {
            return "Score 1 goal";
        }
    }
    

    and use it in Footballer class:

    public class Footballer : Sportsman
    {
        public string ShowGoal(IGoal goal) 
        {
            return goal.Visit(this);
        }
    }
    

    Now we do not have hierarchy tree and we can call it like this:

    new Footballer().GetGoal(new FootballerGoal())
    

    UPDATE:

    There is a good article about Parallel Inheritance Hierarchies.. It proposes some ways to solve this task. Let me show the third way.

    Solution 3 Collapse a hierarchy.

    Pros:

    • Only maintain One hierarchy

    • Easy to maintain

    Cons

    • Breaks SRP fairly often.

    So Footballer class would like this:

    public class Footballer : Sportsman
    {
        public override string ShowGoal()
        {
            return new FootballerGoal().Get();
        }
        
        public string GetGoal()
        {
            return "Score 1 goal";
        }
    }
    

    And Runner class would like this:

    public class Runner : Sportsman
    {
        public override string ShowGoal()
        {
            return new RunnerGoal().Get();
        }
    
        public string GetGoal()
        {
            return "Run 1 km";
        }
    }