Fluent界面 - 返回最具体的返回类型

时间:2013-09-08 01:34:07

标签: java design-patterns fluent return-type

情况:

我有一个看起来有点像这样的类层次结构。请注意,我的确实看起来像这样,我只是用这种方式写它,使它更短,在我看来,更清晰。

public abstract BaseClass {
    private Alpha a;
    private Beta b;

    public Alpha getAlpha() { return a; }
    public Beta getBeta() { return b; }
    public BaseClass setAlpha(Alpha a) { this.a = a; return this; }
    public BaseClass setBeta(Beta b) { this.b = b; return this; }
}

public Foo extends BaseClass {
    @Override
    public Foo setBeta(Beta b) {
        super.setBeta(b);
        doSomethingElse();
        return this;
    }
    public Gamma getGamma() { return g; }
    public Foo setGamma(Gamma g) { this.g = g; return this; }
}

public Bar extends BaseClass {
    private Omega o;
    @Override
    public Bar setAlpha(Alpha a) {
        super.setAlpha();
        doSomethingElse();
        return this;
    }
    public Omega getOmega() { return o; }
    public Bar setOmega(Omega o) { this.o = o; return this; }
}

问题:

上面列出了更多这些方法。请注意,它们不符合相同的接口。使用FooBar且需要调用setGammasetOmega的类始终可以访问最具体的类。但是,这些相同的类还需要调用setAlphasetBeta。但是,除非我覆盖它们,否则这些方法不会返回正确的类型。

选项:

  1. 覆盖BaseClass的每个方法只是为了更改返回类型
    • 似乎有很多不必要的代码
  2. setGamma中声明setOmegaBaseClass抽象等所有方法。这可能有用,除了那时我必须为那些根本没有意义的类定义它。
  3. 与#2类似,除了我没有将这些方法声明为抽象,我给他们一个实现 - throw new UnsupportedOperationException()
  4. 与#3相似,但我只是忽略了问题而不是抛出Exception
  5. 我的所有构建器始终具有最具体的返回类型。即someBar.setOmega().setAlpha()但不是someBar.setAlpha().setOmega()
  6. 所有这些选项看起来都很糟糕。有没有人有更好的东西?

    注意:这种情况与此不太一样:Java - Inherited Fluent method return type to return incident class' type, not parent's因为它不是真正的泛型问题。

1 个答案:

答案 0 :(得分:3)

正如@chrylis在评论中指出的那样,您可以对BaseClass进行泛化:

public abstract class BaseClass<T extends BaseClass> {
    private Alpha a;
    private Beta b;

    public Alpha getAlpha() {
        return a;
    }

    public Beta getBeta() {
        return b;
    }

    @SuppressWarnings("unchecked")
    public T setAlpha(Alpha a) {
        this.a = a;
        return (T) this;
    }

    @SuppressWarnings("unchecked")
    public T setBeta(Beta b) {
        this.b = b;
        return (T) this;
    }
}

并扩展如下:

富:

public class Foo extends BaseClass<Foo> {
    private Gamma g;

    @Override
    public Foo setBeta(Beta b) {
        super.setBeta(b);
        doSomethingElse();
        return this;
    }

    private void doSomethingElse() { }

    public Gamma getGamma() {
        return g;
    }

    public Foo setGamma(Gamma g) {
        this.g = g;
        return this;
    }
}

酒吧:

public class Bar extends BaseClass<Bar> {
    private Omega o;

    @Override
    public Bar setAlpha(Alpha a) {
        super.setAlpha(a);
        doSomethingElse();
        return this;
    }

    private void doSomethingElse() { }

    public Omega getOmega() {
        return o;
    }

    public Bar setOmega(Omega o) {
        this.o = o;
        return this;
    }
}

这引入了一些未经检查的强制警告,我压制了它。它编译,但我还没有尝试过用它做任何事情。