2 回答
TA贡献1865条经验 获得超7个赞
我们不是神圣裁判所的代码法官,所以我们没有责任告诉你,“只做一个空检查就可以”。
当然,可以将 is 写成普通if语句,就像我们过去 25 年所做的那样,就像可以发明一个详细的框架来封装null检查并以某种方式将术语“lambda”带入其中。剩下的唯一问题是你是否真的打算写作if(person != null) { /* do the checks */ },换句话说,让一个null人通过考试。
如果您想拒绝null人员(这会更合理),已经有可能在没有显式测试的情况下编写它Objects.requireNonNull,因为 Java 7,这表明您不需要“一切都变得更好”框架以实现该目标。一般来说,你可以用常规代码合理地编写验证代码,与文章示例相反,使用&&运算符等简单工具,将常用代码放入方法中:
public void validate(Person person) {
Objects.requireNonNull(person, "person is null");
checkString(person.getFirstName(), "first name", 2, 12);
checkString(person.getLastName(), "last name", 4, 30);
checkString(person.getEmail(), "email", 3, 50);
if(!person.getEmail().contains("@"))
throw new IllegalArgumentException("invalid email format");
checkBounds(person.getAge(), "age", 0, 110);
}
private void checkString(String nameValue, String nameType, int min, int max) {
Objects.requireNonNull(nameValue, () -> nameType+" is null");
checkBounds(nameValue.length(), nameType, min, max);
}
private void checkBounds(int value, String valueType, int min, int max) {
if(value < min || value > max)
throw new IllegalArgumentException(valueType+" is not within ["+min+" "+max+']');
}
这与您的代码相同,没有任何名称中带有“Lambda”的框架,仍然具有可读的验证代码并允许重用检查代码。也就是说LamdaPersonValidator,您应该使用反映类职责的类名,而不是反映您如何实现它的类名。显然,负责验证对象某些属性的验证器不应与检查数据库中实体存在的验证器混淆。后者本身就是一个完全不同的话题,也应该是一个单独的问题。
上面的代码只是一个例子,如何实现与原始代码相同。它永远不应该以这种形式出现在生产代码中,因为它展示了一种广泛存在的反模式,将任意不合理的约束应用于属性,很可能是程序员在编写代码时发明的。
为什么它假设一个人必须有名字和姓氏,为什么它假设名字必须至少有两个到十二个字符,而姓氏必须在四到三十个字符之间?
它实际上甚至不是字符,因为char单位和实际字符之间的关联不是 1:1。
对于每个考虑实现名称验证的程序员来说,必须阅读Falsehoods Programmers Being About Names (With Examples)。
同样,维基百科经验证的最年长者名单列出了 100 名 110 岁以上的人。
并且没有理由假设电子邮件地址不能超过五十个字符。一个正确的电子邮件模式的真正的验证可能会变成被什么东西故意省略......
TA贡献1785条经验 获得超8个赞
您也可以像这样编写 GenericValidator:
编写AbstractValidator普通工作类:
public abstract class AbstractValidator {
private Map<Predicate, String> validatorMap = new LinkedHashMap<>();
protected List<String> messages;
public AbstractValidator() {
this.messages = new ArrayList<>();
}
protected <E> AbstractValidator add(Predicate<E> predicate, String reason) {
validatorMap.put(predicate, reason);
return this;
}
protected AbstractValidator apply(String fieldName, Object val) {
AtomicBoolean flag= new AtomicBoolean(true);
this.validatorMap.forEach((modifier, reason) -> {
if (flag.get() && !modifier.test(val)) {
String message = MessageFormat.format("{0} {1}", fieldName, reason);
messages.add(message);
flag.set(false);
}
});
this.validatorMap.clear();
return this;
}
public void end(String exceptionStatus) {
Optional.ofNullable(messages).filter(CollectionUtils::isEmpty)
.orElseThrow(() -> {
RuntimeException ex = new RuntimeException(exceptionStatus, messages);
messages.clear();
return ex;
});
}
}
编写GenericValidator将扩展AbstractValidator验证实现的类:
public class GenericValidator extends AbstractValidator {
private GenericValidator() {
super();
}
public static GenericValidator of() {
return new GenericValidator();
}
public GenericValidator nonNull() {
add(Objects::nonNull, "Field value is null");
return this;
}
public GenericValidator notEmpty() {
add(StringUtils::isNotEmpty, "Field is empty");
return this;
}
public GenericValidator min(int min) {
add(s -> ((String) s).length() >= min, "Field min size is " + min);
return this;
}
public GenericValidator max(int max) {
add(s -> ((String) s).length() <= max, "Field max size is " + max);
return this;
}
public GenericValidator notEmptyList() {
add(CollectionUtils::isNotEmpty, "Field List is null/Empty");
return this;
}
public GenericValidator apply(String fieldName, Object val) {
return (GenericValidator) super.apply(fieldName, val);
}
}
请相应地进行测试。测试用例示例:
class GenericValidatorTest {
@Test
void genericValidationSuccessCase() {
Abc abc = new Abc();
abc.setName("a");
abc.setVal(1);
abc.setAbslist(Collections.singletonList(new ChildAbc()));
GenericValidator of = GenericValidator.of();
of.nonNull().apply("abc", abc).end(GENERIC_JSON_SERIALIZATION);
of.notEmpty().min(1).max(1).apply("name", abc.getName())
.nonNull().apply("value", abc.getVal())
.notEmptyList().apply("childAbc", abc.getAbslist())
.end(GENERIC_JSON_SERIALIZATION);
}
@Test
void genericValidationWhenObjectNull() {
GenericValidator of = GenericValidator.of();
Assertions.assertThrows(BusinessException.class, () -> of.nonNull()
.apply("abc", null).end(GENERIC_JSON_SERIALIZATION));
}
@Test
void genericValidationWithExceptionInput() {
Abc abc = new Abc();
abc.setName("a");
abc.setVal(1);
GenericValidator of = GenericValidator.of();
of.nonNull().apply("abc", abc).end(GENERIC_JSON_SERIALIZATION);
GenericValidator apply = of.notEmpty().min(1).max(1).apply("name", abc.getName())
.nonNull().apply("value", abc.getVal())
.notEmptyList().apply("childAbc", abc.getAbslist());
Assertions.assertThrows(BusinessException.class, () -> apply.end(GENERIC_JSON_SERIALIZATION));
}
}
class Abc {
String name;
Integer val;
List<ChildAbc> abslist;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVal() {
return val;
}
public void setVal(Integer val) {
this.val = val;
}
public List<ChildAbc> getAbslist() {
return abslist;
}
public void setAbslist(List<ChildAbc> abslist) {
this.abslist = abslist;
}
}
class ChildAbc {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
添加回答
举报