如何用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();
原理说明:
- 每个子参数的构建器(
InParam.Builder和OutParam.Builder)在初始化时都会接收父构建器的引用,这样就能知道自己属于哪个父对象的构建上下文。 - 当调用
and()方法时,会先构建出当前的子参数对象,把它添加到父构建器对应的列表中,然后返回父构建器,这样就能继续链式调用其他方法,比如添加另一个参数或者设置父对象的其他属性。 - 我们保留了Lombok的
@Data注解来自动生成getter、setter等方法,减少手动代码量,只自定义了构建器部分来实现流畅的嵌套语法。
备注:内容来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

