前言
最近在《Effective Java》第三版,看到第二条的时候很是有感而发。内容就是标题"遇到多个构造器参数的时候要考虑使用构建器"。这个很多时候我们都会使用到。尤其在属性很多的时候,而且这些属性还需要你去一个个设置。当你想简略的时候使用构造器去简化那么多set方法,但是由于放在构造器里面,在IDE里面你就会发现用起来有时候你会只知道参数的类型不知道参数的意义,尤其是临近两个参数类型一样,你可能错位了都没发现。虽然Idea在智能提示上已经做得不错,能提示入参的属性名。但是如果我们使用构造器会发现更容易的去理解代码赋值的语义。
案例
年末了,公司开始抓指标,开始用sonnar去扫描你的代码。没办法为了那指标只能去优化你那陈年老代码。在扫描过程中发现一个问题被多次提到:
String literals should not be duplicated
产生问题的原因就是我们用公司的校验工具类,它需要传rules进去,这个rules是string类型,它的前面半段是
/**
* 参数校验
*
* @param body 参数
*/
public static void validateBody(AppSubscriptionBody body) {
ValidUtil.valid("应用ID", body.getAppId(), "{'required':true,'regex':'" + RegexConstants.STRING_1_200_PATTERN + "'}");
ValidUtil.valid("算法编码由字母A-Z数字0-9下划线组成", body.getAlgCode(), "{'required':true,'regex':'" + RegexConstants.ALG_CODE + "'}");
.....省略多个参数
}
“{‘required’:true,‘regex’:’”
由于规则开头都是这样,竟然说我应该统一用静态变量去替换。如果你真按照它的建议改,那你是真的蠢。因为这个问题的实质是这个规则的组装不应该用字符串+的方式把它拼接在一起。由于这个参数校验每个项目都有而且占大头,随便就能上百个,所以我决定把规则的字符串生成规则改造一下,用第2条规则去改造它。
import com.alibaba.fastjson.JSONObject;
import com.awifi.capacity.common.constant.RegexConstants;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.StringUtils;
/**
* 正则Json组装类
*
* @author shangjh
* @date 2020-12-1
*/
public class RegularJson {
private Boolean required;
private String regex;
private Numeric numeric;
private Integer length;
@Getter
@Setter
public static class Numeric {
private Long min;
private Long max;
public Numeric(Long min, Long max) {
this.min = min;
this.max = max;
}
}
/**
* 属性构建器
*/
public static class Builder {
private Boolean required = false;
private String regex;
private Numeric numeric;
private Integer length;
public Builder(String regex, Numeric numeric) {
this.regex = regex;
this.numeric = numeric;
}
public Builder required(Boolean required) {
this.required = required;
return this;
}
public Builder regex(String regex) {
this.regex = regex;
return this;
}
public Builder numeric(Long min, Long max) {
this.numeric.setMin(min);
this.numeric.setMax(max);
return this;
}
public Builder length(Integer length) {
this.length = length;
return this;
}
public RegularJson build() {
return new RegularJson(this);
}
}
public RegularJson(Builder builder) {
required = builder.required;
regex = builder.regex;
numeric = builder.numeric;
length = builder.length;
}
public String getRules() {
JSONObject rules = new JSONObject();
rules.put("required", this.required);
if (!StringUtils.isEmpty(regex)) {
rules.put("regex", this.regex);
}
if (numeric != null) {
rules.put("numeric", numeric);
}
if (length != null) {
rules.put("length", length);
}
return rules.toJSONString();
}
}
测试
// ValidUtil.valid("算法服务器端口[port]数字,2-5个数字,", form.getPort(), "{'required':true,'numeric':{'min':10,'max':99999}}");
RegularJson build = new Builder(null, new Numeric(10L, 99999L)).required(true).build();
String rules = build.getRules();
System.out.println(rules);
System.out.println("{'required':true,'numeric':{'min':10,'max':99999}}");
// ValidUtil.valid("算法编码由字母A-Z数字0-9下划线组成", form.getAlgCode(), "{'required':true,'regex':'" + RegexConstants.ALG_CODE + "'}");
RegularJson build2 = new Builder(RegexConstants.ALG_CODE, null).length(18).build();
String rules2 = build2.getRules();
System.out.println(rules2);
System.out.println("{'required':true,'regex':'" + RegexConstants.ALG_CODE + "'}");
结果
{"numeric":{"max":99999,"min":10},"required":true}
{'required':true,'numeric':{'min':10,'max':99999}}
{"regex":"^[0-9A-Z-_]{6,18}$","length":18,"required":false}
{'required':false,'regex':'^[0-9A-Z-_]{6,18}$','length':18,}
测试结果与字符串拼接效果一样。这样那sonnar100多的错误轻松解决,终于可以开心的度过年底检查了。如果你觉得这片文章对您有用,请麻烦您点个小小的赞。您的一个赞就是我继续下去的动力。我会一直不定期分享日常开发过程中的一些有趣的事。