0

I have a class that implements an interface. There's another class that implements this interface, too, and an instance of this second class backs my class's implementation.

For many of the methods specified by the interface, my class simply forwards them straight to the second class.

public class MyClass implements MyInterface
{
    private OtherClass otherClassInstance; // Also implements MyInterface.
    // ...
    void foo() { otherClassInstance.foo(); }
    void bar() { otherClassInstance.bar(); }
    void baz() { otherClassInstance.baz(); }
    // ...
}

Simply deriving my class from the second class would eliminate all of this, but it doesn't make sense because the two classes are unrelated to each other (besides implementing a common interface). They represent different things - it just so happens that a lot of my class's implementation copies that of the other class. In other words, my class is implemented atop the second class, but it is not itself a subset of the second class. As we know, inheritance is meant to express an "is-a" relationship, not to share implementation, so it's inappropriate in this case.

This portion of a talk by Joshua Bloch illustrates the situation well.

I know that Java doesn't have any language support for delegation. However, is there at least some way to clean up my class's implementation so it isn't so redundant?

Maxpm
  • 24,113
  • 33
  • 111
  • 170
  • Lemme get this straight... you want to extend ArrayList, but not in every case and an interface doesn't cut it... It your `MyList` falls down to mostly ArrayList then it would really make sense to extend ArrayList, and handle the non-arraylist lists accordingly. – Shark Apr 02 '13 at 07:40
  • Normally I check the reasons for "MyList". Most of the time, it is an ArrayList and in some cases I need special behaviour. For this situation I use the ArrayList and build Wrapper/Adapter/commands to provide the functionality. And most of the time I look up Guava, and get the needed extentions for free. – Jordi Laforge Apr 02 '13 at 07:42
  • @Shark No, I don't want to extend `ArrayList`. I'm making my own class to implement `List`, and the `ArrayList` member merely backs my implementation. It does *not* make sense for a `MyList` object to be used in place of an `ArrayList` object - ever. – Maxpm Apr 02 '13 at 07:47
  • 1
    "every MyList isn't an ArrayList. They represent different things. It just so happens that MyList copies most of ArrayList's implementation." For me, that is the definition of an ArrayList child: it overrides some methods but most of them are equal. – Pablo Lozano Apr 02 '13 at 08:05
  • You know what you need and why you're doing it that way Maxpm, so maybe you should explain why extending the `ArrayList` is a wrong move? Besides, who would ever use your `MyList` instead of `ArrayList` ? – Shark Apr 02 '13 at 08:14
  • @Shark: No one would want to use `MyList` instead of an `ArrayList`. That's the point. It isn't meant as a substitute. @Pablo: Not exactly. It's not an "is-a" relationship. – Maxpm Apr 02 '13 at 13:12
  • I think maybe you're getting caught up on the example, which is my fault. See my edits, especially the link; it provides a much clearer example. – Maxpm Apr 02 '13 at 13:13
  • Did you really link to an hour-long talk to better illustrate your point ....? You might wanna rethink your 'question asking' strategy a bit. Right now it sounds like your main problem is "my source is too long". – Shark Apr 02 '13 at 13:20
  • @Shark The link directs to a single slide in the talk. If it doesn't work for you for some reason, skip to 0:42:00. – Maxpm Apr 02 '13 at 14:39

2 Answers2

3

An answer which is not really an answer to your actual question:

I'd say, live with the boilerplate. Let IDE generate it for you. Example: in Netbeans, add the private ArrayList field, set cursor to where you'd want the methods to appear, hit alt-insert, select "Generate Delegate Method...", click the methods you want to create a delegate for in the dialog opens, submit, go through the generated methods and make them do the right thing, you're done.

It is a bit ugly, but it is still preferable to starting to mess with reflection, when you are dealing with just one class, like it sounds. Your class is probably the kind of class, which you will complete and fully test, and then hopefully never touch again. Reflection creates runtime cost which does not go away. Suffering the auto-generated boilerplate in the source file is probably preferable in this case.

hyde
  • 60,639
  • 21
  • 115
  • 176
1

First way to use http://java.sun.com/javase/6/docs/api/java/lang/reflect/Proxy.html see tutorial http://docs.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html

Second way using AOP you can create dispatcher that intercept all invocation of specific class

For both ways you need to manage methods processing using reflection API

EDITED TO SHOW IDEA Following code taken from tutorial above just modified a little (see youListImpl.getRealArrayList() in invoke method)

public class DebugProxy implements java.lang.reflect.InvocationHandler {

    private YouListImpl youListImpl;

    public static Object newInstance(Object obj) {
    return java.lang.reflect.Proxy.newProxyInstance(
        obj.getClass().getClassLoader(),
        obj.getClass().getInterfaces(),
        new DebugProxy(obj));
    }

    private DebugProxy(Object obj) {
    this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args)
    throws Throwable
    {
        Object result;
    try {
        System.out.println("before method " + m.getName());
        result = m.invoke(youListImpl.getRealArrayList(), args);
        } catch (InvocationTargetException e) {
        throw e.getTargetException();
        } catch (Exception e) {
        throw new RuntimeException("unexpected invocation exception: " +
                       e.getMessage());
    } finally {
        System.out.println("after method " + m.getName());
    }
    return result;
    }
}
Dewfy
  • 23,277
  • 13
  • 73
  • 121