31

我正在解决一个问题,其中有几个 的实现Foo,伴随着几个FooBuilder's。虽然Foo's 共享几个需要设置的公共变量,但它们也有不同的变量,需要它们各自FooBuilder来实现某些特定的功能。为简洁起见,我想让FooBuilder's setter 使用方法链接,例如:

public abstract class FooBuilder {
  ...

  public FooBuilder setA(int A) {
    this.A = A;
    return this;
  }

  ...
}

public class FooImplBuilder extends FooBuilder{
  ...
  public FooImplBuilder setB(int B) {
    this.B = B;
    return this;
  }
  public FooImplBuilder setC(int C) {
    this.C = C;
    return this;
  }
  ...
}

依此类推,有几种不同的FooBuilder实现。这在技术上可以满足我的所有需求,但是,这种方法在执行方法链接时对方法调用的顺序很敏感。以下有方法未定义的编译错误:

someFoo.setA(a).setB(b)...

要求开发人员考虑链中方法调用的顺序。为了避免这种情况,我想让 setter 以FooBuilder某种方式返回实际的实现子类。但是,我不确定如何执行此操作。最好的方法是什么?

4

3 回答 3

21

这是一个很好的问题,也是一个真正的问题。

正如 Jochen 的回答中提到的,在 Java 中处理它的最简单方法可能涉及使用泛型。

在这篇关于Using Inheritance with Fluent Interfaces的博客文章中有一个很好的讨论和一个合理的解决方案,它将泛型与getThis()构建器子类中覆盖的方法的定义相结合,以解决始终返回正确类的构建器的问题。

于 2012-06-10T13:40:58.053 回答
11

找到这个出色的答案后,我现在分享它。

public class SuperClass<I extends SuperClass>
{
    @SuppressWarnings( "unchecked" ) // If you're annoyed by Lint.
    public I doStuff( Object withThings )
    {
        // Do stuff with things.
        return (I)this ; // Will always cast to the subclass. Causes the Lint warning.
    }
}

public class ImplementationOne
extends SuperClass<ImplementationOne>
{} // doStuff() will return an instance of ImplementationOne

public class ImplementationTwo
extends SuperClass<ImplementationTwo>
{} // doStuff() will return an instance of ImplementationTwo
于 2017-03-01T19:05:01.680 回答
5

泛型可能是这里的方法。

如果你声明 setA() 像这样(伪代码)

<T> T setA(int a)

编译器应该能够找出真正的类型,如果不能,你可以在代码中给出提示,比如

obj.<RealFoo>setA(42)
于 2012-06-10T12:18:54.707 回答