2

I'm developing an application which builds on a class written by another developer (for which I do not have the source).

I wish to use all of the functionality of said class but also to extend it with additional functionality. Ordinarily to achieve this I would have defined an interface (MyInterface) and have extended the external class (TheirClass) from my own (MyClass) while implementing MyInterface.

public interface TheirClassInterface {
    public void theirMethod1();
    public void theirMethod2();
}

public class TheirClass implements TheirClassInterface {
    public void theirMethod1() { ... }
    public void theirMethod2() { ... }
}

public class TheirOtherClass {
    public void theirOtherMethod1(TheirClassInterface o) { ... }
}

public interface MyInterface() {
    public void myMethod1();
}

public class MyClass extends TheirClass implements MyInterface {
    public void myMethod1() { ... }
}

public class MyNewClass extends MyClass {
    public void MyNewClassMethod() { ... }
}

The problem is complicated by the fact that:

  1. I now wish to create a new class (MyNewClass) which adds additional functionality to MyClass but I don't want my code to be dependent on TheirClass.
  2. I wish to be able to use my class as a parameter to the method of TheirOtherClass.

To combat this I refactored my code to instead use composition over inheritance and implementing TheirClassInterface. This works but requires me to implement many methods and delegate them to theirClassObject (in reality TheirClassInterface contains a very large number of methods).

public interface TheirClassInterface {
    public void theirMethod1();
    public void theirMethod2();
}

public class TheirClass implements TheirClassInterface {
    public void theirMethod1() { ... }
    public void theirMethod2() { ... }
}

public class TheirOtherClass {
    public void theirOtherMethod1(TheirClassInterface o) { ... }
}

public interface MyInterface() {
    public void myMethod1();
}

public class MyClass implements TheirClassInterface, MyInterface {
    private TheirClass theirClassObject;

    public void myMethod1() { ... }
    public void theirMethod1() { theirClassObject.theirMethod1(); }
    public void theirMethod2() { theirClassObject.theirMethod2(); }
}

public class MyNewClass extends MyClass {
    public void MyNewClassMethod() { ... }
}

My question is whether my approach is appropriate in this case and whether it could be improved upon as it seems to me that my code uses an excessive amount of delegation to get the job done.

Many thanks for any guidance anyone can give on this.

Danny

Danny
  • 557
  • 5
  • 16
  • 1
    It seems reasonable to me. What you are doing isn't going to be elegant in Java. ;) – Peter Lawrey Aug 03 '12 at 13:22
  • 1
    Does `TheirClass` implement `TheirClassInterface`? – davidfmatheson Aug 03 '12 at 14:42
  • I like Tony's solution below when you have two interfaces with two methods, but why can't you just extend `TheirOtherClass` and implement `MyInterface`? You are dependent on `TheirClass` whether you extend it or use it as a member variable, aren't you? You can still pass it to `TheirOtherClass`, correct? – davidfmatheson Aug 03 '12 at 15:41

3 Answers3

1

First, as java is a strongly-typed single inheritance language, you cannot escape the delegation.

But you can avoid having to write a lot of delegation CODE, by using a dirty little trick with Proxies and reflection. Code follows

public interface Interface1 {
    void m1();
}
public interface Interface2 {
    void m2();
}
public class Class1 implements Interface1 {
    public void m1() {
        System.out.println(1);
    }

}
public class Class2 implements Interface2 {
    public void m2() {
        System.out.println(2);
    }
}
public interface MixinInterface extends Interface1, Interface2 {

}

And this is how the magic happens

package j.with.pseudo.multiple.inheritance;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MixinBuilder {

    public static Object buildMixed(Class _interface, Object... impls){
        InvocationHandler h = new MixinHandler(_interface.getInterfaces(), impls);
        return Proxy.newProxyInstance(MixinBuilder.class.getClassLoader(), 
            new Class[]{_interface}, h);
    }

    public static void main(String[] args) {
        Class1 o1 = new Class1();
        Class2 o2 = new Class2();
        MixinInterface almost_like_multiple_inheritance_guy = 
            (MixinInterface) buildMixed(MixinInterface.class, o1, o2);
        almost_like_multiple_inheritance_guy.m1();
        almost_like_multiple_inheritance_guy.m2();
    }

    private static class MixinHandler implements InvocationHandler{

        private Class[] interfaces;
        private Object[] impls;

        public MixinHandler(Class[] interfaces, Object[] impls) {
            this.interfaces = interfaces;
            this.impls = impls;
        }

        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            int i=0;
            for(Class _interface : interfaces){
                if(method.getDeclaringClass().isAssignableFrom(_interface)){
                    return method.invoke(impls[i], args);
                }
                i++;
            }
            // TODO Auto-generated method stub
            throw new RuntimeException("Method not found: "+method);
        }

    }
}

Pretty cool huh? :-)

Tony Lâmpada
  • 5,301
  • 6
  • 38
  • 50
0

You can't not-depend on a class if you're extending it; it's like having a definition of Human, which does not depend on the definition of Mammal, your optinos are to rewrite everything in the parent, or depend on it.

WhyNotHugo
  • 9,423
  • 6
  • 62
  • 70
0

Many thanks for the answers so far. I've come up with a solution which I think seems reasonable and allows me to fully encapsulate the foreign class.

At the moment I've returned to the method discussed in the first block of code (repeated and extended below) and am now implementing my MyInterface interface for MyNewClass and delegating all interface operations to a composed object. The object to delegate to is decided at runtime by calling a static method on a Factory.

public interface TheirClassInterface {
    public void theirMethod1();
    public void theirMethod2();
}

public class TheirClass implements TheirClassInterface {
    public void theirMethod1() { ... }
    public void theirMethod2() { ... }
}

public class TheirOtherClass {
    public void theirOtherMethod1(TheirClassInterface o) { ... }
}

public interface MyInterface() {
    public void myMethod1();
}

public class MyClass extends TheirClass implements MyInterface {
    public void myMethod1() { ... }
}

public class MyNewClass implements MyInterface {
    private MyInterface myObject;

    public MyNewClass() {
        myObject = MyClassFactory.createMyClass();
    }

    public void myMethod1() {
        myObject.myMethod();
    }

    public void MyNewClassMethod() { ... }
}

Once again, thanks for the ideas. I'm now going to look into them all and see if I can use them to improve my code.

Cheers,

Danny

Danny
  • 557
  • 5
  • 16