Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Fluent接口-返回最具体的返回类型 情况:_Java_Design Patterns_Fluent_Return Type - Fatal编程技术网

Java Fluent接口-返回最具体的返回类型 情况:

Java Fluent接口-返回最具体的返回类型 情况:,java,design-patterns,fluent,return-type,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)

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

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
的类始终可以访问最特定的类。但是,这些类还需要调用
setAlpha
setBeta
。但是,这些方法不会返回正确的类型,除非我重写它们

选项:

  • 重写
    基类的每个方法
    ,只是为了更改返回类型
    • 似乎有很多不必要的代码
  • BaseClass
    中声明每个方法,如
    setGamma
    setOmega
    抽象。这可能行得通,但我必须为那些毫无意义的类定义它
  • 与#2类似,除了我没有将这些方法声明为抽象之外,我给了它们一个实现-
    抛出新的UnsupportedOperationException()
  • 与#3类似,只是我忽略了问题,而不是抛出
    异常
  • 始终首先使用最具体的返回类型。i、 e.
    someBar.setOmega().setAlpha()
    但不
    someBar.setAlpha().setOmega()
  • 所有这些选择似乎都很糟糕。有人有更好的吗


    注意:这种情况与此不同:因为它不是真正的泛型问题。

    正如@chrylis在注释中指出的,您可以泛型化
    基类

    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;
        }
    }
    
    公共抽象类基类{
    私人阿尔法a;
    私人Beta b;
    公共Alpha getAlpha(){
    返回a;
    }
    公共Beta getBeta(){
    返回b;
    }
    @抑制警告(“未选中”)
    公共T组α(αa){
    这个a=a;
    返回(T)这个;
    }
    @抑制警告(“未选中”)
    公共T-setBeta(Beta b){
    这个.b=b;
    返回(T)这个;
    }
    }
    
    并延长如下:

    傅:
    公共类Foo扩展了基类{
    私人伽马g;
    @凌驾
    公共食品展(Beta b){
    super.setBeta(b);
    doSomethingElse();
    归还这个;
    }
    私有void doSomethingElse(){}
    公共Gamma getGamma(){
    返回g;
    }
    公共食品设定伽马(伽马g){
    这个.g=g;
    归还这个;
    }
    }
    
    酒吧:
    公共类栏扩展了基类{
    私人欧米茄o;
    @凌驾
    公共酒吧设置Alpha(Alpha a){
    super.setAlpha(a);
    doSomethingElse();
    归还这个;
    }
    私有void doSomethingElse(){}
    公共Omega getOmega(){
    返回o;
    }
    公共酒吧设置欧米茄(欧米茄o){
    这个。o=o;
    归还这个;
    }
    }
    

    这引入了两个未经检查的强制转换警告,我抑制了它们。它可以编译,但我还没有试着用它做任何事情。

    如果您需要在
    setBeta
    setAlpha
    期间调用
    doSomethingElse()
    ,您没有选择。我想您可以将
    基类
    泛化,并让
    setAlpha/Beta
    返回
    ,但我今晚没时间签名,我有点喜欢这个。我看到的一个问题是,从技术上讲,您可以执行
    公共类Baz扩展基类
    ,这将导致
    类异常
    s。当然我永远不会这么做,但这会让设计容易犯这样愚蠢的错误。是的,不可否认它有点脆弱。如果你的答案是选项6,如果你设计这个系统,你会选择哪个选项?我可能会这样做。它并不完美,但我认为它比其他选择要好。如果你要走这条路,就用基类泛型参数
    代替``。我还建议只以可控的方式使用这种风格,而不是将其应用到整个体系结构中,因为由于泛型问题,Java确实不能很好地处理流畅的接口。
    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;
        }
    }