Java:构建器模式、继承和泛型

标签 java design-patterns

我想通过继承来实现构建器模式。所以我有以下 4 个类:一个抽象类(ClassA)、ClassB、ClassC。 TestTest 类用于查看这一切是如何工作的:

public abstract class ClassA {

    private String aString;

    public String getaString() {
        return aString;
    }

    public abstract class ClassABuilder<T extends ClassABuilder>{

        public T setaString(String str) {
            ClassA.this.aString = str;
            return (T)this;
        }

        public abstract ClassA build();

    }
}

public class ClassB extends ClassA{

    private String bString;

    public String getbString() {
        return bString;
    }

    public class ClassBBuilder<T extends ClassBBuilder> extends ClassA.ClassABuilder<T>{

        public T setbString(String str) {
            ClassB.this.bString = str;
            return (T)this;
        }

        @Override
        public ClassB build(){
            return ClassB.this;
        }
    }
}

public class ClassC extends ClassB{

    private String cString;

    public String getcString() {
        return cString;
    }

    public static ClassCBuilder<ClassCBuilder> newBuilder(){
        return new ClassC().new ClassCBuilder();
    }

    public class ClassCBuilder<T extends ClassCBuilder> extends ClassB.ClassBBuilder<T>{

        public T setcString(String str) {
            ClassC.this.cString = str;
            return (T)this;
        }

        @Override
        public ClassC build(){
            return ClassC.this;
        }
    }
}

public class TestTest {

    public static void main(String[] args) {
        // TODO code application logic here
        ClassC C=ClassC.newBuilder()
                .setaString(null)
                .setbString(null)
                .setcString(null) //LINE XXX
                .build();
    }
}

问题是,在 LINE XXX 的 TestTest 中,我找不到符号“setcString”。我做错了什么?

最佳答案

让我们沿着层次结构追踪它:

首先考虑这个签名:

class ClassABuilder<T extends ClassABuilder>

当您调用setaString(null)时返回的T将是一个扩展 ClassABuilder 的对象。编译器知道这是一个 ClassBBuilder这样您就可以调用 setbString(null) .

但是,由于定义规定 T需要扩展 raw ClassBBuilder仅关于 ClassBBuilder 的任何信息的泛型类型将会丢失。因此编译器只知道 TClassBBuilder但并不是说它实际上是 ClassCBuilder延伸ClassBBuilder<ClassCBuilder>因此不知道 setcString()关于返回的类型。

正如已经提到的,使用T extends ClassABuilder<T>将解决这个问题,因为现在编译器知道还有另一个泛型类型要沿着层次结构传递。

newBuilder()那么必须看起来像这样:

public static ClassCBuilder<?> newBuilder(){
    //you have too create a raw type here so you'll have to ignore/suppress/live with the warning
    return (new ClassC().new ClassCBuilder());
}

关于Java:构建器模式、继承和泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42977031/

相关文章:

java - 带有 java Applet 的嵌套 Jar

c# - 如何在自分层树结构中的每个节点执行业务规则

c++ - 如何使用C++中的装饰器模式在一行代码中装饰对象?

c++ - 以下情况应遵循的设计模式

java - 基于瓦片的碰撞检测,物体穿过瓦片掉落

java - 如何从一个单元格检查所有可到达的单元格

java - 使用反射复制构造函数

java - 类似的输入对话框创建模式/Swing

oop - 表示派生类上的 "container"派生自基类容器的设计模式

java - kafka- Producer-perf-test.sh 有多少个生产者?