Search code examples
javamultiple-inheritancediamond-problem

Any established practices on overcoming the lack of multiple inheritance in Java?


I have a classic diamond inheritance problem where

   A
 /   \
B     C
 \   /
   D

are all interfaces, and I have

AImpl(A)
|       \
|        \
BImpl(B)  CImpl(C)
|          \
|           \
DImpl(B,C)   \
|             F(C)
|
E(B,C)

where class E implements both interfaces B and C, but F implements only interface C.

Due to the lack of multiple inheritance, I currently have duplicated functionality in DImpl and CImpl.

I just fixed a bug in CImpl, but forgot to do the same for DImpl. Obviously remembering to always copy code from CImpl to DImpl and vice versa is not very sustainable as the code base keeps growing. Are there any established best practices for putting the shared code of both in a single place, despite the disallowance of multiple inheritance?

EDIT -- Solution with multiple inheritance would have been to have DImpl inherit CImpl.cFunction() instead of redefining DImpl.cFunction as a copy of CImpl.cFunction

EDIT 2 -- Sample code:

public interface Animal {
  public void eat();
}

public interface FlyingAnimal extends Animal {
  public void fly();
}

public interface RunningAnimal extends Animal {
  public void run();
}

public interface Monster extends FlyingAnimal, RunningAnimal {
  public void roar();
}

public class AnimalImpl implements Animal {
  @Override
  public void eat() {
    ...
  }
}

public class FlyingAnimalImpl extends AnimalImpl implements FlyingAnimal {
  @Override
  public void fly() {
    ...
  }
}

public class RunningAnimalImpl extends AnimalImpl implements RunningAnimal {
  @Override
  public void run() {
    ...
  }
}

public class MonsterImpl extends FlyingAnimalImpl implements Monster {
  @Override
  public void run() {
    ...
  }

  @Override
  public void roar() {
    ...
  }
}

public class ScaryMonster extends MonsterImpl implements Monster {
  public void sneakAround() {
    ...
  }
}

public class Human extends RunningAnimalImpl implements RunningAnimal {
  public void scream() {
    ...
  }
}

Now if I find a bug in RunningAnimalImpl.run() and I fix it, I have to remember to copy the fix over to MonsterImpl.run().


Solution

  • This is a very poor design. You should not have a diamond structure in the first place just because it is possible in interfaces.

    One of the basic principle of OOP is

    Prefer composition over inheritance!

    What I am saying is you don't need interface D at all. Wherever you need to use DImpl simply provide reference to interface A and then based on your runtime need pass BIml or CImpl instance to it. That way all you have to change is BImpl code or CImpl code for bug fix and it will be used anywhere you are using DImpl instance today.

    As per your comment the code would be something like -

    public class ScaryMonster {
      Animal animal;
      public  ScaryMonster(Animal animal) {
          this.animal = animal;
      }
    
      public void fly() {
          if(animal instanceof FlyingAnimal ) {
            ((FlyingAnimal )animal).fly();
          }
          else {
            throw new Exception("This mosnter cannot fly");
          }     
      }
    
      public void run() {
        if(animal instanceof RunningAnimal ) {
            ((RunningAnimal )animal).run();
          }
          else {
            throw new Exception("This mosnter cannot run");
          }
      }
    
      public void sneakAround() {
        ...
      }
    }
    

    If you want your monster to both fly and run pass instance of MonsterImpl to the constructor. Note now ScaryMonster does not extend or implement anything.

    This is what I am saying - Prefer composition over Inheritance!.