假设您有这样的课程:
public class CreateUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
我们这里有一个字段“userName”,它有一些约束,所以有些值是可以的,有些不是。你也有一堂课EditUserRequest
。您将用户userName
作为用户标识符,因此您EditUserRequest
肯定会使用此字段:
public class EditUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
并且您肯定希望能够删除用户:
public class DeleteUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
所有这些类都有一个具有绝对相似含义和相似约束的字段“userName”。有一天,您决定还允许在userName
s 中使用更多符号。因此,您必须手动修复所有这 3 个类。
解决方案#1
为所有这些请求创建一个基类:
public abstract AbstractUserRequest {
...
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String userName;
...
}
public class CreateUserRequest extends AbstractUserRequest {
... // OK, we have userName here
}
优点:
- 您现在只需修复约束一次
- 创建新类型的请求非常简单,只需子类化
AbstractUserRequest
就可以了。
缺点:
- 如果您需要
userName
其他地方,则必须有一个子类AbstractUserRequest
(例如:CreateUserGroupRequest
它需要一个userName
s 列表,当然您要先验证它们) - 不确定如何正确测试
解决方案#2
为每种类型的字段创建单独的类,以便当您谈论“用户名”时,您知道它不仅仅是 a String
,它是一个 constrained String
:
public class UserNameField {
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
private final String value;
...
}
public class CreateUserRequest {
...
private UserNameField userName;
...
}
优点:
- 如果用户名限制发生变化,您只需修复一次
- 您有一个易于测试的简单类
缺点:
- 感觉有点矫枉过正(?)
解决方案#3(更新)
Hibernate 验证器允许约束组合,以便您可以为一组约束命名:
@NotNull
@Size(min = 4, max = 16)
@Pattern(regexp = "^[a-zA-Z0-9]+$")
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface UserName {
String message() default "{com.loki2302.constraints.username}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
...
public class CreateUserRequest {
...
@UserName
private final String userName;
...
}
优点:
- 简单而强大的方法
- 易于使用(没有额外的抽象)
- 易于测试
缺点:
- 应该没有吧?
这里的常用方法是什么?解决方案 #2看起来不错吗?你是怎么做到的?