有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

JAVA从继承生成器模式返回父对象继承

我相信这个问题可能已经得到了回答,但环顾四周后,我不确定正确的术语是否能给我一个可靠的答案。要么是这个,要么是我没有完全理解

我试图创建一组具有不同方法的构建器,但是,它们都必须从“基本”构建器继承。这很好,但我无法让它返回正确的对象以继续构建器模式

我尝试过的一个例子:

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) 个答案

  1. # 1 楼答案

    根据Type Erasure的定义

    Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded.

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

  2. # 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等的原理相同

  3. # 3 楼答案

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

    string += string创建一个新的StringBuilder,这意味着每次调用Builder#append方法时都要创建一个

    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定义了如何与所有构建器交互。如果您不希望Builder1append3,那么基本接口不应该定义它

  4. # 4 楼答案

    哈哈!我刚刚经历了这些。多痛苦啊。这对我有用。它位于基类中。然而,我将T传递回基类。通过重写每个子类中的方法,每个类都返回自己的类型,可以获得相同的效果

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