覆盖链式方法

时间:2014-11-07 11:44:16

标签: java

让我们使用一个对链接有用的方法A

class A {
  A foo() {
    // do stuff
    return this;
  }
}

您现在可以执行a.foo().foo().foo()(想想:构建器模式)。让B级扩展它:

class B extends A {
}

B b;

现在调用b.foo()会返回实际类型B,但会声明A。因此我不能写:

B other = b.foo();

我必须写:

B other = (B) b.foo();

或覆盖B中的foo()

class B extends A {
  @Override
  B foo() {
    super.foo();
    return this;
  }
}

有一个很好的方法吗?

4 个答案:

答案 0 :(得分:1)

通过对超类实现额外的泛型方法as(type)来实现这一点。这有助于为流畅的界面提供更好的演员。

class A {
    public A foo() {
        return this;
    }
    @SuppressWarnings("unchecked")
    public <T extends A> T as(Class<T> clazz) {
        return (T) this;
    }
}

class B extends A  {}

所以你可以写a.foo().as(B.class).methodOfB(..)。而且您不需要在所有子类中重新实现foo()。

答案 1 :(得分:1)

很抱歉,但是你没有列出最好的方式:

B other = (B) b.foo();

这将是任何开发人员的解决方案,他们使用类AB

覆盖,以便其他开发人员只需编写B other = b.foo();

但实际上编译器没有其他方法可以知道,

  • B 排序 A
  • B兼容,因此您在实例化A但未将其置于B
  • 时不会使用任何信息

最后一个是您必须明确强制转换的原因。示例:

 int myInt = 2;
 short myShort = (short) myInt; // correct

虽然这有效,但编译器需要您明确,因为在许多情况下(当myInt很大时),在转换为short时会丢失精度/信息。

如果这个可行:

short myShort = myInt;   // wrong

然后编译器会自己做出假设。但只有开发人员可以知道,myInt是否会有一个大于short的值。

答案 2 :(得分:1)

您可以声明class A具有其实现类的泛型类型参数,foo()可以返回此动态类型:

class A<T extends A<T>> {
    @SuppressWarnings("unchecked")
    T foo() {
        // do stuff
        return (T) this;
    }
}

class B extends A<B> {
    B bar() {
        // do other stuff
        return this;
    }
}

在此之后,以下内容有效:

B b = new B();
b.foo().bar();

答案 3 :(得分:0)

我认为执行此操作的好方法是将引用保留为类型A,因为这是具有所需功能的最不具体的类:

A other = b.foo();

如果B包含一些必需的功能,则只应转换为类型B:

B another = (B)A;
another.somethingElse();

这与以下逻辑相同:

List<String> myList = new ArrayList<>();

比以下更令人满意:

ArrayList<String> myList = new ArrayList<>();