JAVA返回父对象 - 继承继承 - Builder Pattern

时间:2017-07-31 20:34:26

标签: java parent-child builder extends return-type

我确信这个问题可能已经得到了解答,但在环顾四周后,我不确定是否有正确的术语来为我提供一个可靠的答案。无论是这个,还是我都没有完全理解。

我正在尝试创建一系列具有不同方法的构建器,但是,它们必须都从“base”构建器继承。这很好,但是我无法让它返回正确的对象来继续构建器模式。

我尝试过的一个例子:

public class Builder1 {
    protected String string = new String();

    public <T extends Builder1 > T append1(String string) {
        this.string += string;
        return (T)this;
    }

    public void print() {
        System.out.println(this.string);
    }

}


public class Builder2 extends Builder1 {

    public <T extends builder2 > T append2(String string) {
        this.string += string;
        return (T)this;
    }

}


public class Builder3 extends Builder2 {

    public <T extends Builder3 > T append3(String string) {
        this.string += string;
        return (T)this;
    }

}

所以,如果我这样做:

 new Builder3().append3("")...

我可以访问Builder3,Builder2和Builder1中的所有方法 - 很棒 当我访问Builder1或Builder2中的一个方法时会出现问题,如下所示:

 new Builder3().append1("")...

现在,我只能访问Builder1的方法,而且无法访问Builder2或Builder3。

正如我所说,我确信这已经在其他地方得到了解答所以请随时向我指出任何关于它的帖子。
对此有任何帮助将非常感谢,谢谢。

修改
我还应该指出,这些方法都将做不同的事情。我的例子让他们在不同的地方做同样的事情。

4 个答案:

答案 0 :(得分:2)

[免责声明:未经测试的代码] 我会做一个定义基本append*方法的抽象基类。 ABC看起来像......

public abstract class BaseBuilder {

    protected String string = "";

    public void print() {
        System.out.println(this.string);
    }

    abstract <T extends BaseBuilder> T append1(String string);

    abstract <T extends BaseBuilder> T append2(String string);

    abstract <T extends BaseBuilder> T append3(String string);

}

然后,对于Builder1,您可以实现append1(..),并为其他人抛出异常。

public class Builder1 extends BaseBuilder {
    public <T extends Builder1> T append1(String string) {
        this.string += string;
        return (T)this;
    }

    public <T extends Builder1> T append2(String string) {
        throw new UnsupportedOperationException("something");
    }

    public <T extends Builder1> T append3(String string) {
        throw new UnsupportedOperationException("something");
    }
}

Builder2Builder3等原则相同

答案 1 :(得分:1)

首先,您应该使用StringBuilder来附加文字,而不是String string = new String()

string += string会创建一个新的StringBuilder,这意味着每次调用Builder#append方法时都会创建一个。{/ p>

class Builder1 {
    private StringBuilder builder = new StringBuilder();

    public Builder1 append1(String text) {
        builder.append(text);
        return this;
    }

    public String build() {
        return builder.toString();
    }
}

接下来,您应该知道BaseBuilder接口应该只公开所有构建器所具有的行为。您不应该为此界面定义append2append3。它应该只包含build

interface Builder<T> {
    T build();
}

最后,对于解决方案,您应该decorating添加功能。

你会Builder1

class Builder1 implements Builder<String> {
    private StringBuilder builder = new StringBuilder();

    public Builder1 append1(String text) {
        builder.append(text);
        return this;
    }

    @Override
    public String build() {
         return string.toString();
    }
}

Builder1本身表达了你应该如何继续为其他建设者进行装饰:

  • Builder1由它自己的构建器组成。
  • 将调用委托给该构建器,但会返回当前实例。

Builder2将由Builder1

组成
class Builder2 implements Builder<String> {
    private Builder1 builder = new Builder1();

    public Builder2 append(String text) {
        builder.append(text);
        return this;
    }

    public Builder2 append2(String text) {
        //custom behavior
        return this;
    }

    public String build() {
        return builder1.build();
    }
}

Builder3将由Builder2

组成
class Builder3 implements Builder<String> {
    private Builder2 builder = new Builder2();

    public Builder3 append1(String text) {
        builder.append1(text);
        return this;
    }

    public Builder3 append2(String text) {
        builder.append2(text);
        return this;
    }

    // custom append3

    // build() returns builder.build()
}

存在用于交互的接口:Builder定义所有构建器如何与之交互。如果您不希望Builder1拥有append3,那么基本接口不应该定义它。

答案 2 :(得分:0)

LOL!我刚刚经历过这个。太痛苦了。这适合我。它位于基类中。但是,我将T传递回基类。您可以通过覆盖每个子类中的方法来获得相同的效果,每个类都返回自己的类型。

/**
 * Return this as type T. This is used by fluent setters and build.
 * 
 * @return
 */
@SuppressWarnings("unchecked")
protected T fetchThisAsT() {
    return (T) this;
}

答案 3 :(得分:0)

根据Type Erasure定义

  

如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。

因此,在append1()之后,返回类型实际上是Builder1。要在append2之后append3append1,您可以在所有3个类中将<T extends Builder*>更改为<T extends Builder3>