Java继承多层次层次结构中的Fluent方法返回类型 [英] Java inherited Fluent method return type in multiple level hierarchies

查看:213
本文介绍了Java继承多层次层次结构中的Fluent方法返回类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以在以下的讨论如何正确地模拟自我类型来实现像您正在尝试的分层流畅构建器模式做的。其中,我指出需要在所有中间类型中维护一个变量self-type(代码中的 S ) - 只能用叶类这被理解为 final 。您的代码违反了该规则,因为中间类型 Foo Bar FooImpl 过早解决 S



以下解决方案解决了此问题:

 静态接口BaseFoo< T,S扩展BaseFoo< T,S>> {
S foo();
}

静态接口Foo< T,S扩展Foo< T,S>>扩展BaseFoo< T,S> {
void foo1();
}

静态接口BaseBar< T,S扩展了BaseBar< T,S>>扩展BaseFoo< T,S> {
S bar();
}

静态界面Bar< T,S扩展Bar< T,S>>扩展BaseBar< T,S> {
void bar1();
}

静态抽象类AbstractFooBase< T,S扩展BaseFoo< T,S>>实现BaseFoo< T,S> {
abstract void internalFoo();
@Override
public S foo(){
internalFoo();
return(S)this;
}
}

静态抽象类AbstractIntermediateFoo< T,S扩展AbstractIntermediateFoo< T,S>>扩展AbstractFooBase< T,S>实施Foo< T,S> {
@Override
void internalFoo(){
System.out.println(inside FooImpl :: internalFoo());
}

@Override
public void foo1(){
System.out.println(inside FooImpl :: foo1());
}
}

static final class FooImpl< T>扩展AbstractIntermediateFoo< T,FooImpl< T>> {}

静态抽象类AbstractBarBase< T,S扩展AbstractBarBase< T,S>>扩展AbstractIntermediateFoo< T,S>实现BaseBar< T,S> {
abstract void internalBar();
@Override
public S bar(){
internalBar();
return(S)this;
}
}

static final class BarImpl< T>扩展AbstractBarBase< T,BarImpl< T>>实现Bar< T,BarImpl< T>> {
@Override
void internalBar(){
System.out.println(BarImpl :: internalBar());
}

@Override
public void bar1(){
System.out.println(inside BarImpl :: bar1());



public static void main(String [] args){
FooImpl< String> foo = new FooImpl< String>();
foo.foo()。foo1();

BarImpl<布尔> bar = new BarImpl< Boolean>();
bar.foo()。bar1();
}

我的更改如下:


  • Foo

  • 中维护 S
  • Bar
  • 中维护 S
  • 拆分 FooImpl 添加到以下内容中:


    • AbstractIntermediateFoo ,它是 abstract ,维护 S ,并实现 internalFoo foo1

    • FooImpl ,具体来说, code>并解析 S


  • 使 BarImpl final

  • main ,将 foo bar 声明为 FooImpl BarImpl - 编码到接口在这里不可行。


So following the solution described in Java - Inherited Fluent method return type to return incident class' type, not parent's. I want to extend it to multiple levels.

The solution works in one level obviously. Here is compiled and runnable code (no dependencies):

public enum X {
    ;
    static interface BaseFoo<T, S extends BaseFoo<T, S>> {
        S foo();
    }

    static interface Foo<T> extends BaseFoo<T, Foo<T>> {
        void foo1();
    }

    static abstract class AbstractFooBase<T, S extends BaseFoo<T, S>> implements BaseFoo<T, S> {
        abstract void internalFoo();
        @Override
        public S foo() {
            internalFoo();
            return (S)this;
        }
    }

    static class FooImpl<T> extends AbstractFooBase<T, Foo<T>> implements Foo<T> {
        @Override
        void internalFoo() {
            System.out.println("inside FooImpl::internalFoo()");
        }

        @Override
        public void foo1() {
            System.out.println("inside FooImpl::foo1()");
        }
    }

    public static void main(String[] args) {
        Foo<String> foo = new FooImpl<String>();
        foo.foo().foo1();
    }
}

However things getting difficult when I add an new level in the object inheritance hierarchy. The code below won't compile:

public enum X {
    ;
    static interface BaseFoo<T, S extends BaseFoo<T, S>> {
        S foo();
    }

    static interface Foo<T> extends BaseFoo<T, Foo<T>> {
        void foo1();
    }

    static interface BaseBar<T, S extends BaseBar<T, S>> extends BaseFoo<T, S> {
        S bar();
    }

    static interface Bar<T> extends BaseBar<T, Bar<T>> {
        void bar1();
    }

    static abstract class AbstractFooBase<T, S extends BaseFoo<T, S>> implements BaseFoo<T, S> {
        abstract void internalFoo();
        @Override
        public S foo() {
            internalFoo();
            return (S)this;
        }
    }

    static class FooImpl<T> extends AbstractFooBase<T, Foo<T>> implements Foo<T> {
        @Override
        void internalFoo() {
            System.out.println("inside FooImpl::internalFoo()");
        }

        @Override
        public void foo1() {
            System.out.println("inside FooImpl::foo1()");
        }
    }

    static abstract class AbstractBarBase<T, S extends BaseBar<T, S>> extends FooImpl<T> implements BaseBar<T, S> {
        abstract void internalBar();
        @Override
        public S bar() {
            internalBar();
            return (S)this;
        }
    }

    static class BarImpl<T> extends AbstractBarBase<T, Bar<T>> implements Bar<T> {
        @Override
        void internalBar() {
            System.out.println("inside BarImpl::internalBar()");
        }

        @Override
        public void bar1() {
            System.out.println("inside BarImpl::bar1()");
        }
    }

    public static void main(String[] args) {
        Foo<String> foo = new FooImpl<String>();
        foo.foo().foo1();

        Bar<Boolean> bar = new BarImpl<Boolean>();
        bar.foo().bar1();
    }
}

The compile time error message is:

X.java:40: X.BaseFoo cannot be inherited with different arguments: <T,S> and <T,X.Foo<T>>
    static abstract class AbstractBarBase<T, S extends BaseBar<T, S>> extends FooImpl<T> implements BaseBar<T, S> {
                    ^
X.java:49: X.BaseFoo cannot be inherited with different arguments: <T,X.Bar<T>> and <T,X.Foo<T>>
    static class BarImpl<T> extends AbstractBarBase<T, Bar<T>> implements Bar<T> {
           ^
Note: X.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
2 errors

Any idea how to work around it?

解决方案

This is your inheritance hierarchy:

As you can see, some of these types are inheriting the same interface type more than once. In fact, BarImpl implements BaseFoo four times over, and some of the inheritance chains provide differing arguments for its type parameter S. It can be said that BarImpl implements the following:

  • BaseFoo<T, Foo<T>> (via Foo)
  • BaseFoo<T, Foo<T>> (via FooImpl)
  • BaseFoo<T, Bar<T>> (via Bar)
  • BaseFoo<T, Bar<T>> (via BarImpl)

The same interface cannot be implemented with different type arguments, so you get a compiler error.

As I pointed out on your followup question, my answer here discusses how to properly emulate the "self-type" to implement a hierarchical fluent builder pattern like you're trying to do. In it, I point out the need to maintain a variable "self-type" (S in your code) in all intermediate types - only resolving it with a "leaf class" that is understood to be final. Your code is violating that rule because the intermediate types Foo, Bar, and FooImpl are prematurely resolving S.

The following solution resolves the issue:

static interface BaseFoo<T, S extends BaseFoo<T, S>> {
    S foo();
}

static interface Foo<T, S extends Foo<T, S>> extends BaseFoo<T, S> {
    void foo1();
}

static interface BaseBar<T, S extends BaseBar<T, S>> extends BaseFoo<T, S> {
    S bar();
}

static interface Bar<T, S extends Bar<T, S>> extends BaseBar<T, S> {
    void bar1();
}

static abstract class AbstractFooBase<T, S extends BaseFoo<T, S>> implements BaseFoo<T, S> {
    abstract void internalFoo();
    @Override
    public S foo() {
        internalFoo();
        return (S)this;
    }
}

static abstract class AbstractIntermediateFoo<T, S extends AbstractIntermediateFoo<T, S>> extends AbstractFooBase<T, S> implements Foo<T, S> {
    @Override
    void internalFoo() {
        System.out.println("inside FooImpl::internalFoo()");
    }

    @Override
    public void foo1() {
        System.out.println("inside FooImpl::foo1()");
    }
}

static final class FooImpl<T> extends AbstractIntermediateFoo<T, FooImpl<T>> { }

static abstract class AbstractBarBase<T, S extends AbstractBarBase<T, S>> extends AbstractIntermediateFoo<T, S> implements BaseBar<T, S> {
    abstract void internalBar();
    @Override
    public S bar() {
        internalBar();
        return (S)this;
    }
}

static final class BarImpl<T> extends AbstractBarBase<T, BarImpl<T>> implements Bar<T, BarImpl<T>> {
    @Override
    void internalBar() {
        System.out.println("inside BarImpl::internalBar()");
    }

    @Override
    public void bar1() {
        System.out.println("inside BarImpl::bar1()");
    }
}

public static void main(String[] args) {
    FooImpl<String> foo = new FooImpl<String>();
    foo.foo().foo1();

    BarImpl<Boolean> bar = new BarImpl<Boolean>();
    bar.foo().bar1();
}

My changes were the following:

  • Maintain S in Foo
  • Maintain S in Bar
  • Split FooImpl into the following:
    • AbstractIntermediateFoo, which is abstract, maintains S, and implements internalFoo and foo1.
    • FooImpl, which is concrete, final, and resolves S.
  • Make BarImpl final.
  • In main, declare foo and bar as FooImpl and BarImpl - coding to interface isn't feasible here.

这篇关于Java继承多层次层次结构中的Fluent方法返回类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆