2012-07-11 26 views
2

使用相同的约束假设你有这样一个类:在多个类

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 s中使用更多符号。所以,你必须手动修复所有这三个类。

解决方案#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秒的列表,用于确定要首先确认他们)
  • 不excactly知道如何测试这个正确

SOLUT离子#2

制作单独的类为每个类型的字段,这样当你谈论的“用户名”,你知道这是不是只是一个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; 
    ... 
} 

优点

  • 如果用户名称限制变更,您只需要修复一次
  • 你有一个简单的类,这是很容易测试

缺点

  • 感觉就像矫枉过正(?)

溶液#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看起来不错吗? 怎么办?

+0

现在是在编译之前用gcc预处理文件的时候,或者您的解决方案2在设计方面看起来不错。 – nhahtdh 2012-07-11 05:02:48

回答

3

我肯定会去解决方案#2。正如您在上面演示的那样,您可能希望在不是请求的类中使用UserNameField,这使得AbstractRequest类感觉像是一个稍差的选择。
创建一个类以避免重复的代码,并获得同一地点的所有逻辑听起来对我来说是一个很好的主意,而不是矫枉过正。

[EDIT加入溶液#3后]
溶液#3看起来像的溶液#2一个非常好的变化。我无法真正决定我更喜欢哪一个,他们在封装逻辑方面做得很好。

+1

+1这是使用[value对象](http://c2.com/cgi/wiki?ValueObject)封装约束和相关功能的完美示例。 – casablanca 2012-07-11 05:12:06

+0

刚刚更新了问题,解决方案#3如何? – agibalov 2012-07-11 05:14:35

+0

@Keppil:我也是,基本上:-)看起来#3更好,因为它和#2一样,并且不增加间接级别。但我同意,#2和#3非常相似。 – agibalov 2012-07-11 05:34:37