3

I have one main interface and an abstract class implementing all "derivable" methods (that can be written using only abstract methods) of it:

public interface Main {
    public void main1(int x);
    public void main2();
}

public abstract class MainAbstract implements Main {
    public void main2() { main1(42); }
}

This functionality can be extended in different "directions":

public interface SubA extends Main {
     public void subA1(int x);
     public void subA2();
}

public interface SubB extends Main {
     public void subB1(int x);
     public void subB2();
}

Now I could have abstract classes SubAAbstract and SubBAbstract implementing all the "derivable" methods (like main2 in Main). The problem is that I may have concrete implementations who want to implement both SubA and SubB, so I could use only one of the abstract classes. In reality the problem is worse, because I have more than 2 sub-interfaces.

I'm aware that there is no way around single inheritance in Java, but I would like to know if there is a good way to minimize code duplication in that case.

[Edit]

Would it be an abomination to put all functionality in the MainAbstract class (note that it only implements Main), e.g.

public abstract class MainAbstract implements Main {

    public void main2() {
        main1(42);
    }

    public void subA1(int x) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void subA2() {
        subA1(4711);
    }

    public void subB1(int x) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void subB2() {
        subB1(-1);
    }

}

Then a concrete class needs just to implement the needed interfaces, and to implement the needed methods:

public class MainConcrete extends MainAbstract implements Main, SubA {

    public void main1(int x) {
        System.out.println("main " + x);
    }

    public void subA1(int x) {
        System.out.println("subA" + x);
    }

}

Of course this would only make sense if the hierarchy is rather stable (that means, the sub interfaces are known exactly before), but this would be the case for me. Having the superfluous methods visible isn't nice either, but I don't seee a way to change that.

Landei
  • 54,104
  • 13
  • 100
  • 195
  • There are ways to do it reflectively, at runtime, using AOP, but I'll only post that as a suggestion if you want me to :) – skaffman May 30 '11 at 09:44
  • ah Java and inheritance... You do know it's impossible to satisfy the *equals* and *hashcode* guarantees and hence you'll have to be very careful with your "objects" because, for example, they won't work with the default Java collections anymore? You're also totally wrong when you state *"there is now way around single inheritance in Java"* but it is no surprise: by reading your question it is pretty obvious that you mistake inheritance with "code reuse". Multiple interface inheritance is MI. OO languages that *only* have the equivalent of interface inheritance are fine with it btw. – SyntaxT3rr0r May 30 '11 at 11:22
  • @SyntaxT3rr0r: `equals` and `hashcode` are no problem here, my object make not much sense in a collection. Concerning inheritance I think you can cover the type system aspect of MI using interfaces, but not the "extended functionality" aspect of MI. Either way, something is missing which **could** be there (see e.g. Scala traits or extension method proposal) – Landei May 30 '11 at 11:44

3 Answers3

2

I would like to know if there is a good way to minimize code duplication in that case.

I believe the standard answer would be to use object composition.

Related questions:

Community
  • 1
  • 1
aioobe
  • 413,195
  • 112
  • 811
  • 826
0

Externalize the work to utility classes, builders etc.

Stephan
  • 4,395
  • 3
  • 26
  • 49
0

With objweb asm bytecode-library, you could write an utility that reads the code from all methods, and fields of all your implementing classes and puts them into one class.

The util would look something like this public class ClassUtil {

public static Class<?> unifyClass(Class<?>...classes) {
    return ...;
}
}

And then

Class<?> subAllClass = unifyClass(SubA.class, SubB.class, ...);
Tag
  • 286
  • 2
  • 5