3

这里我们有多个使用相关语法的自定义查询 DSL。我正在创建一个AbstractBuilder,以便所有的共性都可以写在一个地方。问题在于这会导致方法链接出现问题。当我尝试从一个方法链接到AbstractBuilder一个子类时,如果不进行强制转换,它就无法工作。

使用这些课程:

class AbstractBuilder{
    protected final StringBuilder bldr = new StringBuilder();

    AbstractBuilder addValue( String name, String value ){
        bldr.append( name ).append( '=' ).append( value )append( ',' );
        return this;
    }

    String toString(){
        return bldr.toString();
    }
}

class IntBuilder extends AbstractBuilder{

    IntBuilder addValue( String name, int value ){
        bldr.append( name ).append( '=' ).append( value )append( ',' );
        return this;
    }
}

这有效

new IntBuilder().addValue( "age", 12 ).addValue( "name", "Bruce" ).toString();` but `new IntBuilder().addValue( "name", "Bruce" ).addValue( "age", 12 ).toString();

除非你做出丑陋的演员表,否则不会:

((IntBuilder) (new IntBuilder().addValue( "name", "Bruce" ))).addValue( "age", 12 ).toString();

现在我想我可以重写每个方法并通过调用他们的父母(通过super.addValue( name, value );)来实现它们,但这真的很难看。

我怎样才能让每个方法都返回当前类而不是定义它的类?

4

2 回答 2

7

您可以使用泛型来实现这一点。

class BaseBuilder<B extends BaseBuilder>{
    protected final StringBuilder bldr = new StringBuilder();
    private Class<B> builderImplementationClass;

    protected BaseBuilder( Class<B> builderImpl ){
        builderImplementationClass = builderImpl;

        if( this.getClass() != builderImpl )
            throw new IllegalStateException( "Should match." );
    }

    B addValue( String name, String value ){
        bldr.append( name ).append( '=' ).append( value )append( ',' );
        return builderImplementationClass.cast( this );
    }

    String toString(){
        return bldr.toString();
    }
}

class IntBuilder extends AbstractBuilder<IntBuilder>{

    public IntBuilder(){
        super( IntBuilder.class );
    }

    IntBuilder addValue( String name, int value ){
        bldr.append( name ).append( '=' ).append( value )append( ',' );
        return this;
    }
}

基本上,您使所有方法都返回一个类型的值,B并确保将B其设置为您当前的实现

于 2012-12-14T21:38:29.233 回答
1

ArtB 的解决方案很好,但您可以使用以下方法使其更简单:

private static class AbstractBuilder <T extends AbstractBuilder<T>> {
    protected StringBuilder bldr = new StringBuilder();

    public T addValue( String name, String value ){
        bldr.append( name ).append( '=' ).append( value ).append(',');
        @SuppressWarnings("unchecked")
        T result = (T)this;
        return result;
    }

    public String toString(){
        return bldr.toString();
    }
}

private static class IntBuilder extends AbstractBuilder<IntBuilder> {

    public IntBuilder addValue( String name, int value ){
        bldr.append( name ).append( '=' ).append( value ).append(',');
        return this;
    }
}

注意我还用两个私有 StringBuilder 变量修复了这个错误,这几乎肯定不是你想要的。

于 2012-12-14T21:48:21.123 回答