如何减少委托样板?

时间:2013-04-02 07:34:55

标签: java oop delegation boilerplate

我有一个实现接口的类。还有另一个类实现了这个接口,第二个类的实例支持我的类的实现。

对于接口指定的许多方法,我的类只是将它们直接转发到第二个类。

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

简单地从第二个类派生我的类将消除所有这一切,但它没有意义,因为这两个类彼此无关(除了实现一个通用接口)。它们代表了不同的东西 - 我的班级很多实现都复制了其他类的实现。换句话说,我的类是在第二个类的顶层实现的,但它本身不是第二个类的子集。我们知道,继承意味着表达“is-a”关系,而不是分享实现,因此在这种情况下它是不合适的。

约书亚布洛赫演讲的This部分说明了情况。

我知道Java对委派没有任何语言支持。但是,至少有一些方法来清理我的类的实现,所以它不是那么多余吗?

2 个答案:

答案 0 :(得分:3)

答案并非真正回答您的实际问题:

我会说,住在样板上。让IDE为您生成它。示例:在Netbeans中,添加私有ArrayList字段,将光标设置到您希望方法出现的位置,点击alt-insert,选择“ Generate Delegate Method ... ”,单击方法你想要在对话框中创建一个委托,打开,提交,完成生成的方法并让它们做正确的事,你就完成了。

这有点难看,但是当你只处理一个类时,它仍然更好地开始混淆反射,就像听起来一样。你的课程可能是那种课程,你将完成并完全测试,然后希望永远不再触摸。反射会产生不会消失的运行时成本。在这种情况下,最好在源文件中使用自动生成的样板文件。

答案 1 :(得分:1)

使用http://java.sun.com/javase/6/docs/api/java/lang/reflect/Proxy.html的第一种方法见教程http://docs.oracle.com/javase/1.4.2/docs/guide/reflection/proxy.html

使用AOP的第二种方法是创建调度程序来拦截特定类的所有调用

对于这两种方式,您需要使用反射API管理方法处理

编辑显示想法 以下从上面的教程中获取的代码只是修改了一下(请参阅invoke方法中的youListImpl.getRealArrayList())

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;
    }
}