至少需要指定两个属性的构建器模式
Builder pattern that requires at least two properties to be specified
我正在编写 RequestBuilder
class,它将根据以下条件处理查询字符串的创建
- 类别 (
String
)
- 国家(
String
)
- 关键词(
String[]
)
- 页数(
int
)
- pageSize (
int
)
由于并非所有条件都是强制性的并且它们之间有很多组合(我数了 7 个,其中只有 4 个应该有效 - 原因见下文),我决定使用构建器模式:
public class RequestBuilder {
private String category = "";
private String country = "&country=us";
private String keywords = "";
private String page = "";
private String pageSize = "&pageSize=100";
public RequestBuilder() {
}
private String buildQuery() {
return this.category + this.country + this.keywords + this.page + this.pageSize;
}
// the setter methods, which I omitted for readability
但是有个问题。我需要强制用户在构建对象之前至少指定 category
、country
或 keywords
中的两个(现在用户甚至没有义务指定一个!)。例如,用户不应该仅通过指定 country
来创建对象。
那么我该如何强制这个要求呢?如果我创建三个构造函数(每个构造函数都有两个参数),我觉得我正在破坏构建器模式,即使还有三个可选属性需要指定。
作为设计师,您需要决定哪些字段是真正需要的。没有“可能需要”这样的东西。要使用构建器模式并强制执行所需参数,请将字段标记为 final
并通过构造函数注入它们:
public class Request {
// fields
private final String requiredField;
private final String optional1;
private final String optional2;
private Request(RequestBuilder builder) {
requiredField = builder.requiredField;
optional1 = builder.optional1;
optional2 = builder.optional2;
}
// add only getter method to the Request class (builds immutable Request objects)
public static class RequestBuilder {
private final String requiredField;
private String optional1;
private String optional2;
public RequestBuilder(String requiredField) {
this.requiredField = requiredField;
}
public RequestBuilder setOptional1(String optional1) {
this.optional1 = optional1;
return this;
}
public RequestBuilder setOptional2(String optional2) {
this.optional2 = optional2;
return this;
}
public Request build() {
return new Request(this);
}
}
}
生成器强制执行必填字段和可选字段。构建器正在构建的对象隐藏了构造函数,因此只能通过构建器访问它。请求对象中的字段都是最终的不变性。
要使用,您需要执行以下操作:
RequestBuilder builder = new RequestBuilder("required");
Request request = builder.setOptional1("foo").setOptional2("bar").build();
或者您可以在调用构建器构造函数后随时调用 build()
。
更新:
现在解决您的问题....您可以(可能)修改 build()
以检查您拥有多少个“半必填”字段值并将其与字段总数进行比较。对我来说,这是一个黑客。为此,您有两个选择
- 对字段数进行硬编码并检查总数中有多少仍然为空。如果未设置的字段数低于某个计数,则抛出一些异常(即
InvalidRequiredFieldCount
)。否则,您 return 新实例。为此,您需要在每次调用 setter 方法时增加“计数”。
- 使用反射获取字段列表(数组)并使用此字段并使用此字段计数来计算“必填”字段的最小数量。如果未达到最小阈值,则抛出异常;如果达到最小阈值,则 return 一个新的请求实例。
public Request build() throws Exception {
Request request = new Request(this);
int count = 0;
int max = 2;
Field[] allFields = Request.class.getDeclaredFields();
for (Field field : allFields) {
Object o = field.get(request);
if (o != null) {
count++;
}
}
if (count < 2) {
throw new Exception("Minimum number of set fields (2) not reached");
}
return request;
}
这不是很漂亮,但是很管用。如果我 运行 这个:
RequestBuilder builder = new RequestBuilder("required");
Request request = builder.build();
会导致异常:
Exception in thread "main" java.lang.Exception: Minimum number of set fields (2) not reached
at com.master.oxy.Request$RequestBuilder.build(Request.java:54)
at com.master.oxy.Request.main(Request.java:63)
但是,如果我设置至少一个可选的,新实例将被 returned。
我正在编写 RequestBuilder
class,它将根据以下条件处理查询字符串的创建
- 类别 (
String
) - 国家(
String
) - 关键词(
String[]
) - 页数(
int
) - pageSize (
int
)
由于并非所有条件都是强制性的并且它们之间有很多组合(我数了 7 个,其中只有 4 个应该有效 - 原因见下文),我决定使用构建器模式:
public class RequestBuilder {
private String category = "";
private String country = "&country=us";
private String keywords = "";
private String page = "";
private String pageSize = "&pageSize=100";
public RequestBuilder() {
}
private String buildQuery() {
return this.category + this.country + this.keywords + this.page + this.pageSize;
}
// the setter methods, which I omitted for readability
但是有个问题。我需要强制用户在构建对象之前至少指定 category
、country
或 keywords
中的两个(现在用户甚至没有义务指定一个!)。例如,用户不应该仅通过指定 country
来创建对象。
那么我该如何强制这个要求呢?如果我创建三个构造函数(每个构造函数都有两个参数),我觉得我正在破坏构建器模式,即使还有三个可选属性需要指定。
作为设计师,您需要决定哪些字段是真正需要的。没有“可能需要”这样的东西。要使用构建器模式并强制执行所需参数,请将字段标记为 final
并通过构造函数注入它们:
public class Request {
// fields
private final String requiredField;
private final String optional1;
private final String optional2;
private Request(RequestBuilder builder) {
requiredField = builder.requiredField;
optional1 = builder.optional1;
optional2 = builder.optional2;
}
// add only getter method to the Request class (builds immutable Request objects)
public static class RequestBuilder {
private final String requiredField;
private String optional1;
private String optional2;
public RequestBuilder(String requiredField) {
this.requiredField = requiredField;
}
public RequestBuilder setOptional1(String optional1) {
this.optional1 = optional1;
return this;
}
public RequestBuilder setOptional2(String optional2) {
this.optional2 = optional2;
return this;
}
public Request build() {
return new Request(this);
}
}
}
生成器强制执行必填字段和可选字段。构建器正在构建的对象隐藏了构造函数,因此只能通过构建器访问它。请求对象中的字段都是最终的不变性。
要使用,您需要执行以下操作:
RequestBuilder builder = new RequestBuilder("required");
Request request = builder.setOptional1("foo").setOptional2("bar").build();
或者您可以在调用构建器构造函数后随时调用 build()
。
更新:
现在解决您的问题....您可以(可能)修改 build()
以检查您拥有多少个“半必填”字段值并将其与字段总数进行比较。对我来说,这是一个黑客。为此,您有两个选择
- 对字段数进行硬编码并检查总数中有多少仍然为空。如果未设置的字段数低于某个计数,则抛出一些异常(即
InvalidRequiredFieldCount
)。否则,您 return 新实例。为此,您需要在每次调用 setter 方法时增加“计数”。 - 使用反射获取字段列表(数组)并使用此字段并使用此字段计数来计算“必填”字段的最小数量。如果未达到最小阈值,则抛出异常;如果达到最小阈值,则 return 一个新的请求实例。
public Request build() throws Exception {
Request request = new Request(this);
int count = 0;
int max = 2;
Field[] allFields = Request.class.getDeclaredFields();
for (Field field : allFields) {
Object o = field.get(request);
if (o != null) {
count++;
}
}
if (count < 2) {
throw new Exception("Minimum number of set fields (2) not reached");
}
return request;
}
这不是很漂亮,但是很管用。如果我 运行 这个:
RequestBuilder builder = new RequestBuilder("required");
Request request = builder.build();
会导致异常:
Exception in thread "main" java.lang.Exception: Minimum number of set fields (2) not reached
at com.master.oxy.Request$RequestBuilder.build(Request.java:54)
at com.master.oxy.Request.main(Request.java:63)
但是,如果我设置至少一个可选的,新实例将被 returned。