This is something thatâs usually taught to first year Java students. Though I had a small mental blank about how it was implemented. I knew that to get around the âlimitationâ*, you could specify a class with multiple interfaces, but that was only half the solution. What about the implementation?
Surprisingly it was hard to get a clear answer from the fractal patterns that Google found, a lot of developers saying, âoh yeah, you need interfacesâ but it didnât sound like they knew themselves.
So, this was my way, probably duplicated a zillion times, but here you go, hereâs a way:
We are going to have three classes, A, B & C (sorry for the lack of imaginative names here). Class C will extend both A & B. Weâll extra interfaces for A & B dubbed Ai & Bi respectively.
First an interface for the classes we are going to âextendâ from.
1: public interface Ai {
2: public void aMethod();
3: }
1: public interface Bi {
2: public void bMethod();
3: }
and now some implementation:
1: public class A implements Ai {
2:
3: public void aMethod() {
4: System.out.println("aMethod");
5: }
6:
7: }
1: public class B implements Bi {
2: public void bMethod() {
3: System.out.println("bMethod");
4: }
5: }
And now for our binding class, C. The class implements both interfaces, and takes in implementations of each of the super-classes as constructor arguments. The implementations of each method defined in the A and B interface is a delegate to the relevant A or B class that was injected in the constructor.
1: public class C implements Ai, Bi {
2: private final Ai a;
3: private final Bi b;
4:
5: public C(Ai a, Bi b) {
6: this.a = a;
7: this.b = b;
8: }
9:
10: public void aMethod() {
11: a.aMethod();
12: }
13:
14: public void bMethod() {
15: b.bMethod();
16: }
17: }
The call to the implementing a.aMethod() is effectively a super() call. You can then append your own extra implementation, or remove the delegating call and define your own.
So what about the diamond problem, when both A & B define a method that is named that same thing. In Java if you try to say a class implements interfaces that have duplicate signatures youâll get a compile time error. If Ai and Bi both had a method called cMethod() then the C class would refuse to compile.
Other ways
My research found other mentions. If you got lazy, you could have C extend A, and implement Bi. Then you wouldnât have to write the interface Ai and C would be a little smaller since it would only inject the B implementation and have a bMethod() delegate.
Another way was to have the 2nd class as a static inner class. Although I have no issue with this implementation working, as soon as I see âinnerâ, Iâm led to believe its re-use value becomes a bit more limited and certainly more cumbersome to refer to.
Notes
BTW, if you want to find a decent explanation of what to do and an interesting reading of a Mixin pattern implemented in Java, then see here.
* I say âlimitationâ in quotes because apart from the well known diamond inheritance problem that crops up with multiple inheritance in C++, from what I read, using multiple inheritance could be a code smell. Certainly the ambiguity that comes from not knowing exactly which one will be called or whether or not youâll know at compile time, or run-time is a concern. (Donât delay the Bad-news)