2012-07-11 53 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