2

情况:

我有一个看起来有点像这样的类层次结构。请注意,我的看起来并不这样,我只是以这种方式编写它以使其更短,并且在我看来更清晰。

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

问题:

上面列出了更多这些方法。请注意,它们不符合相同的接口。使用和需要调用的类Foo总是Bar可以setGamma访问setOmega最具体的类。但是,那些相同的类也需要调用setAlphaand setBeta。但是,除非我重写它们,否则这些方法不会返回正确的类型。

选项:

  1. 覆盖BaseClassjust 的每个方法以更改返回类型
    • 似乎有很多不必要的代码
  2. 声明每个方法 likesetGammasetOmegaabstract in BaseClass。这可能会起作用,除非我必须为那些根本没有意义的类定义它。
  3. 与#2 类似,除了我没有将这些方法声明为抽象之外,我给它们一个实现 -throw new UnsupportedOperationException()
  4. 与 #3 类似,除了我只是忽略问题而不是抛出Exception.
  5. 总是我的所有构建器都首先具有最具体的返回类型。即someBar.setOmega().setAlpha()但不是someBar.setAlpha().setOmega()

所有这些选项看起来都很恶心。有人有更好的吗?

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

4

1 回答 1

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

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

于 2013-09-08T11:46:35.373 回答