2017-07-31 182 views
2

我敢肯定,这个问题可能已经回答,但环顾四周后,我不确定正确的术语让我一个坚实的答案。无论是这个,还是我没有完全理解的东西。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。

正如我所说,我相信这已经在其他地方得到了回答,所以请随时指点我任何有关它的帖子。
任何帮助,将不胜感激,谢谢。

编辑:
我还要指出的是,这些方法都将做不同的事情。我的例子看起来好像他们在不同的地方做同样的事情。

+0

首先,您应该遵循Java命名约定。班级名称**总是**以大写字母开头! –

+0

是的,对不起,我通常这样做,但这只是一个例子,但我会进行编辑。 :P – user3208218

回答

0

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

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

[声明:未测试的代码] 我要这么做定义的基append*方法的抽象基类。农行看起来像......

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

+0

我理解这种方法,但它正在做一些我想要避免的事情。我希望它继承整个方法的原因是因为基类中有很多它们,我不想每次都写出它们。在使用每个构建器(The Java Assist/Intellisense thing)时,我也不想看到IDE中不支持的方法。感谢您的意见,但。 – user3208218

1

要开始了,你应该使用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,那么基本接口不应该定义它。

0

按照Type Erasure定义

替换泛型类型所有类型参数与他们的界限或对象,如果类型参数是无限的。

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