You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Lombok为包含嵌套成员列表的类实现流畅的链式构建语法?

如何用Lombok为包含嵌套成员列表的类实现流畅的链式构建语法?

嘿,Jason,我来帮你实现你想要的这种流畅链式构建写法!

首先,你现有的Lombok @Builder生成的构建器只能通过inParams()方法传入整个列表,或者用@Singular生成的addInParam()方法逐个添加,但没法像你期望的那样嵌套构建子参数然后无缝回到父构建器。要实现你想要的那种.inParam().xxx().and()的语法,我们需要自定义构建器,让子参数的构建器持有父构建器的引用,这样就能通过and()方法回到父构建的上下文。

先看看你现有的类结构:

@Data
@Builder
public class DatabaseCallInformation {

    private String dbPackage;
    private String dbProcedure;
    private List<InParam> inParams;
    private List<OutParam> outParams;

    @Data
    @Builder
    public static class InParam {
        
        private String paramName;
        private int sqlType;
        private String value;

    }

    @Data
    @Builder
    public static class OutParam {
        
        private String paramName;
        private int sqlType;
        private SqlReturnType sqlReturnType;
        private RowMapper<?> rowMapper;

    }
}

接下来我们修改这个类,自定义构建器来实现你想要的流畅语法:

@Data
public class DatabaseCallInformation {

    private String dbPackage;
    private String dbProcedure;
    private List<InParam> inParams;
    private List<OutParam> outParams;

    @Data
    public static class InParam {
        private String paramName;
        private int sqlType;
        private String value;

        // InParam的构建器,持有父构建器引用
        public static class Builder {
            private final DatabaseCallInformation.Builder parentBuilder;
            private String paramName;
            private int sqlType;
            private String value;

            public Builder(DatabaseCallInformation.Builder parentBuilder) {
                this.parentBuilder = parentBuilder;
            }

            public Builder paramName(String paramName) {
                this.paramName = paramName;
                return this;
            }

            public Builder sqlType(int sqlType) {
                this.sqlType = sqlType;
                return this;
            }

            public Builder value(String value) {
                this.value = value;
                return this;
            }

            // 回到父构建器,并将当前InParam添加到列表
            public DatabaseCallInformation.Builder and() {
                parentBuilder.inParams.add(this.build());
                return parentBuilder;
            }

            public InParam build() {
                InParam inParam = new InParam();
                inParam.setParamName(paramName);
                inParam.setSqlType(sqlType);
                inParam.setValue(value);
                return inParam;
            }
        }
    }

    @Data
    public static class OutParam {
        private String paramName;
        private int sqlType;
        private SqlReturnType sqlReturnType;
        private RowMapper<?> rowMapper;

        public static class Builder {
            private final DatabaseCallInformation.Builder parentBuilder;
            private String paramName;
            private int sqlType;
            private SqlReturnType sqlReturnType;
            private RowMapper<?> rowMapper;

            public Builder(DatabaseCallInformation.Builder parentBuilder) {
                this.parentBuilder = parentBuilder;
            }

            public Builder paramName(String paramName) {
                this.paramName = paramName;
                return this;
            }

            public Builder sqlType(int sqlType) {
                this.sqlType = sqlType;
                return this;
            }

            public Builder sqlReturnType(SqlReturnType sqlReturnType) {
                this.sqlReturnType = sqlReturnType;
                return this;
            }

            public Builder rowMapper(RowMapper<?> rowMapper) {
                this.rowMapper = rowMapper;
                return this;
            }

            public DatabaseCallInformation.Builder and() {
                parentBuilder.outParams.add(this.build());
                return parentBuilder;
            }

            public OutParam build() {
                OutParam outParam = new OutParam();
                outParam.setParamName(paramName);
                outParam.setSqlType(sqlType);
                outParam.setSqlReturnType(sqlReturnType);
                outParam.setRowMapper(rowMapper);
                return outParam;
            }
        }
    }

    // 自定义父构建器
    public static class Builder {
        private String dbPackage;
        private String dbProcedure;
        private List<InParam> inParams = new ArrayList<>();
        private List<OutParam> outParams = new ArrayList<>();

        public Builder dbPackage(String dbPackage) {
            this.dbPackage = dbPackage;
            return this;
        }

        public Builder dbProcedure(String dbProcedure) {
            this.dbProcedure = dbProcedure;
            return this;
        }

        // 创建InParam构建器,传入当前父构建器引用
        public InParam.Builder inParam() {
            return new InParam.Builder(this);
        }

        // 创建OutParam构建器
        public OutParam.Builder outParam() {
            return new OutParam.Builder(this);
        }

        public DatabaseCallInformation build() {
            DatabaseCallInformation info = new DatabaseCallInformation();
            info.setDbPackage(dbPackage);
            info.setDbProcedure(dbProcedure);
            info.setInParams(inParams);
            info.setOutParams(outParams);
            return info;
        }
    }

    // 提供静态builder入口方法
    public static Builder builder() {
        return new Builder();
    }
}

现在你就可以完全按照你期望的方式来构建对象了:

DatabaseCallInformation result = DatabaseCallInformation.builder()
    .dbPackage("MY_PACKAGE")
    .dbProcedure("MY_PROCEDURE")
    .inParam()
        .paramName("ID")
        .sqlType(Types.NUMBER)
        .and()
    // 可以继续添加更多入参
    .inParam()
        .paramName("USER_NAME")
        .sqlType(Types.VARCHAR)
        .value("JASON")
        .and()
    .outParam()
        .paramName("result")
        .sqlType(Types.VARCHAR)
        .and()
    .build();

原理说明:

  1. 每个子参数的构建器(InParam.Builder和OutParam.Builder)在初始化时都会接收父构建器的引用,这样就能知道自己属于哪个父对象的构建上下文。
  2. 当调用and()方法时,会先构建出当前的子参数对象,把它添加到父构建器对应的列表中,然后返回父构建器,这样就能继续链式调用其他方法,比如添加另一个参数或者设置父对象的其他属性。
  3. 我们保留了Lombok的@Data注解来自动生成getter、setter等方法,减少手动代码量,只自定义了构建器部分来实现流畅的嵌套语法。

备注:内容来源于stack exchange,提问作者Jason

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 09:58:08