假装你有一个类似这样的课程:
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
中使用更多符号。因此,您必须手动修复所有这3个类。
为所有这些请求创建基类:
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
的列表,确定你想先验证它们)为每种类型的字段创建单独的类,这样当您谈论“用户名”时,您知道它不仅仅是String
,而是受约束的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;
...
}
赞成:
缺点:
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 看起来不错吗? 你怎么做?
答案 0 :(得分:3)
我肯定会选择解决方案#2 。如上所示,您可能希望在非请求的类中使用UserNameField
,这会使AbstractRequest
类感觉更糟糕。
创建一个类来避免重复代码并将所有逻辑放在同一个地方听起来对我来说是一个很好的主意,并且根本不会过分。
[添加解决方案#3后编辑]
解决方案#3 看起来像解决方案#2 的非常好的变体。我无法真正决定哪一个我更喜欢,他们都能很好地封装逻辑。