0

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

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

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”关系,而不是共享实现,所以在这种情况下是不合适的。

Joshua Bloch 演讲的这一部分很好地说明了这种情况。

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

4

2 回答 2

3

一个答案并不是对您的实际问题的真正答案:

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

这有点难看,但当你只处理一个类时,它仍然比开始弄乱反射更可取,就像听起来一样。您的课程可能是您将完成并全面测试的课程,然后希望永远不会再碰它。反射会产生不会消失的运行时成本。在这种情况下,在源文件中遭受自动生成的样板文件可能是更可取的。

于 2013-04-02T07:57:25.273 回答
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 管理方法处理

编辑显示想法 以下代码从上面的教程中得到了一些修改(参见调用方法中的 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;
    }
}
于 2013-04-02T07:47:05.193 回答