如何让对象的自定义构建器设置几个字段?
How to have custom builder for Object to set few fields?
我有一个 class Data
,其中包含列表和两个变量(id
和 name
)。我正在用列表值替换变量。列表中的第一个将是 id
和 name
的新值。删除 id
和 name
后,请求对象将仅包含 dataList
。但问题是这个变量在很多地方都被使用了。我正在考虑在 Request 对象中创建 id 和 name 属性的 setter。
我创建了 getter,但不确定如何创建 setter,以便我将项目添加到同一对象的列表中。此外,如何单独覆盖这两个字段的构建器。假设请求对象也很大。
Class Request
@Builder
@Getter
public class Request {
private String id; //need to removed
private String name; //need to removed
private List<Data> dataList;
public String getId() {
return (dataList != null) ? dataList.get(0).getId() : null;
}
public String getName() {
return (dataList != null) ? dataList.get(0).getName() : null;
}
}
Class Data
:
public class Data {
private String id;
private String name;
}
当有人调用 setId 或 setName 时,应该更新 dataList 中索引 0 处的项目。
我如何为生成器做同样的事情?
如果很多地方都在调用Request对象。您可以替换 Request 对象中的 id 和 name 属性的 setter。重写Request对象中id和name属性的setter方法时,可以调用Data对象的setter方法写入
你只需要重写set方法并在方法中设置值
public void setId(String id) {
if (dataList == null) {
dataList = new ArrayList(2);
}
if (null == dataList.get(0)) {
dataList.add(0, new Data());
}
dataList.get(0).setId(id);
}
覆盖 Lombok 的 setter 不会改变构建器的行为,您必须同时覆盖它们。让我们从更难的开始:
建设者
通过定义构建器的骨架,Lombok 的构建器很容易被覆盖。不会生成现有部分,Lombok 仅完成构建器。在 Request
:
中创建一个嵌套的 class
public static class RequestBuilder {
public final RequestBuilder id(final String id) {
this.id = id;
updateData(id, name, dataList);
return this;
}
public final RequestBuilder name(final String name) {
this.name = name;
updateData(id, name, dataList);
return this;
}
}
什么是updateData
?您需要在每个构建器的方法调用中更新 dataList
。该方法必须是 static
否则静态构建器无法访问它。在 Request
class:
中定义它
private static void updateData(final String id, final String name, List<Data> dataList) {
if (dataList == null) {
dataList = new ArrayList<>();
}
if (dataList.isEmpty()) {
dataList.add(new Data(id, name));
} else {
var data = dataList.get(0);
data.setId(id);
data.setName(name);
}
}
你的dataList
是null
的情况没有处理,所以我宁愿在这里初始化它(因此方法的形式参数中的字段不能是最终的)。
Setter
这很简单,您需要做与在构建器中基本相同的事情 - 只需重写正确的方法即可:
public final void setId(final String id) {
this.id = id;
updateData(id, getName(), dataList);
}
public final void setName(final String name) {
this.name = name;
updateData(getId(), name, dataList);
}
大功告成。为了简单起见,我用 Lombok 注释 @lombok.Data
(注意名称)和 @AllArgsConstructor
.
对 class Data
进行了注释
测试
至少编写一些单元测试来覆盖和验证行为始终是一个好习惯。我需要用 @AllArgsConstructor
注释 Request
以避免调用作为测试对象的 setter。我还需要一些有用的方法来断言和消除代码重复:
void assertRequestBeforeTest(final Request request) {
assertThat(request.getId(), nullValue());
assertThat(request.getName(), nullValue());
assertThat(request.getDataList(), hasSize(0));
}
void assertRequestAfterTest(final Request request, final String id, final String name) {
assertThat(request.getId(), is(id));
assertThat(request.getName(), is(name));
assertThat(request.getDataList(), notNullValue());
var data = request.getDataList().get(0);
assertThat(data, notNullValue());
assertThat(data.getId(), is(id));
assertThat(data.getName(), is(name));
}
和测试:
@Test
void setter_onNullFields() {
var request = new Request(null, null, new ArrayList<>());
assertRequestBeforeTest(request);
request.setId("id-new");
request.setName("name-new");
assertRequestAfterTest(request, "id-new", "name-new");
}
@Test
void setter_onExistingFields() {
var request = new Request("id", "name", new ArrayList<>());
assertRequestBeforeTest(request);
request.setId("id-new");
request.setName("name-new");
assertRequestAfterTest(request, "id-new", "name-new");
}
@Test
void builder() {
var requestBuilder = Request.builder().dataList(new ArrayList<>());
var request = requestBuilder.id("id-new").name("name-new").build();
assertRequestAfterTest(request, "id-new", "name-new");
}
我有一个 class Data
,其中包含列表和两个变量(id
和 name
)。我正在用列表值替换变量。列表中的第一个将是 id
和 name
的新值。删除 id
和 name
后,请求对象将仅包含 dataList
。但问题是这个变量在很多地方都被使用了。我正在考虑在 Request 对象中创建 id 和 name 属性的 setter。
我创建了 getter,但不确定如何创建 setter,以便我将项目添加到同一对象的列表中。此外,如何单独覆盖这两个字段的构建器。假设请求对象也很大。
Class Request
@Builder
@Getter
public class Request {
private String id; //need to removed
private String name; //need to removed
private List<Data> dataList;
public String getId() {
return (dataList != null) ? dataList.get(0).getId() : null;
}
public String getName() {
return (dataList != null) ? dataList.get(0).getName() : null;
}
}
Class Data
:
public class Data {
private String id;
private String name;
}
当有人调用 setId 或 setName 时,应该更新 dataList 中索引 0 处的项目。
我如何为生成器做同样的事情?
如果很多地方都在调用Request对象。您可以替换 Request 对象中的 id 和 name 属性的 setter。重写Request对象中id和name属性的setter方法时,可以调用Data对象的setter方法写入
你只需要重写set方法并在方法中设置值
public void setId(String id) {
if (dataList == null) {
dataList = new ArrayList(2);
}
if (null == dataList.get(0)) {
dataList.add(0, new Data());
}
dataList.get(0).setId(id);
}
覆盖 Lombok 的 setter 不会改变构建器的行为,您必须同时覆盖它们。让我们从更难的开始:
建设者
通过定义构建器的骨架,Lombok 的构建器很容易被覆盖。不会生成现有部分,Lombok 仅完成构建器。在 Request
:
public static class RequestBuilder {
public final RequestBuilder id(final String id) {
this.id = id;
updateData(id, name, dataList);
return this;
}
public final RequestBuilder name(final String name) {
this.name = name;
updateData(id, name, dataList);
return this;
}
}
什么是updateData
?您需要在每个构建器的方法调用中更新 dataList
。该方法必须是 static
否则静态构建器无法访问它。在 Request
class:
private static void updateData(final String id, final String name, List<Data> dataList) {
if (dataList == null) {
dataList = new ArrayList<>();
}
if (dataList.isEmpty()) {
dataList.add(new Data(id, name));
} else {
var data = dataList.get(0);
data.setId(id);
data.setName(name);
}
}
你的dataList
是null
的情况没有处理,所以我宁愿在这里初始化它(因此方法的形式参数中的字段不能是最终的)。
Setter
这很简单,您需要做与在构建器中基本相同的事情 - 只需重写正确的方法即可:
public final void setId(final String id) {
this.id = id;
updateData(id, getName(), dataList);
}
public final void setName(final String name) {
this.name = name;
updateData(getId(), name, dataList);
}
大功告成。为了简单起见,我用 Lombok 注释 @lombok.Data
(注意名称)和 @AllArgsConstructor
.
Data
进行了注释
测试
至少编写一些单元测试来覆盖和验证行为始终是一个好习惯。我需要用 @AllArgsConstructor
注释 Request
以避免调用作为测试对象的 setter。我还需要一些有用的方法来断言和消除代码重复:
void assertRequestBeforeTest(final Request request) {
assertThat(request.getId(), nullValue());
assertThat(request.getName(), nullValue());
assertThat(request.getDataList(), hasSize(0));
}
void assertRequestAfterTest(final Request request, final String id, final String name) {
assertThat(request.getId(), is(id));
assertThat(request.getName(), is(name));
assertThat(request.getDataList(), notNullValue());
var data = request.getDataList().get(0);
assertThat(data, notNullValue());
assertThat(data.getId(), is(id));
assertThat(data.getName(), is(name));
}
和测试:
@Test
void setter_onNullFields() {
var request = new Request(null, null, new ArrayList<>());
assertRequestBeforeTest(request);
request.setId("id-new");
request.setName("name-new");
assertRequestAfterTest(request, "id-new", "name-new");
}
@Test
void setter_onExistingFields() {
var request = new Request("id", "name", new ArrayList<>());
assertRequestBeforeTest(request);
request.setId("id-new");
request.setName("name-new");
assertRequestAfterTest(request, "id-new", "name-new");
}
@Test
void builder() {
var requestBuilder = Request.builder().dataList(new ArrayList<>());
var request = requestBuilder.id("id-new").name("name-new").build();
assertRequestAfterTest(request, "id-new", "name-new");
}