2013-05-05 58 views
0

假設一個Java類名爲Car,其對象通過靜態工廠初始化:最佳實踐TDD - Java對象驗證和乾淨的代碼

public class Car { 

    private String name; 

    private Car(String name){//...} 

    public static Car createCar(String name){ 
     //mechanism to validate the car attributes 
     return new Car(name); 
    } 
} 

當然,我想提取驗證過程到一個名爲專用類CarValidator

有提供這種驗證工廠的方式有兩種:

不stubbable/mockable驗證

public static Car createCar(String name){ 
    new CarValidator(name); // throw exception for instance if invalid cases 
    return new Car(name); 
} 

Stubbable/mockable驗證:

public static Car createCar(CarValidator carValidator, String name){ //ideally being an interface instead 
    carValidator.validate(); 
    return new Car(name); 
} 

它在這裏看起來很像冗餘:CarValidator已經包含name值,因爲它存儲Car參數作爲自己的字段(先驗乾淨的方式),因此,我們可以繞過這樣的第二個參數:

public static Car createCar(CarValidator carValidator){ 
    carValidator.validate(); 
    return new Car(carValidator.getName()); 
} 

然而,這看起來不清楚......爲什麼一個Car發現它的價值從Validator =>沒有意義。

所以,我們可以refactorate這樣的:

public static Car createCar(CarValidator carValidator, String name){ 
         carValidator.validate(name); // throwing exception for instance if invalid cases 
         return new Car(carValidator.name()); 
} 

聽起來很少怪異,但CarValidator失去從創建字段,而不是參數傳遞給它的每一個必要的私有方法,如受益:

private checkForCarName(String name); 

我應該選擇哪種方法?

回答

1

我的建議如下: 我不會混合領域對象的驗證與對象本身。

如果域對象假設傳遞給它的數據是有效的,並且驗證應該在其他地方執行(例如在工廠中,但不是必需的),那將更清晰。在該「工廠」中,您將執行數據準備狀態(驗證,漏洞刪除等),然後您將創建一個新對象。

您將能夠測試工廠(如果它正確驗證),而不是域對象本身。

+0

對不起,但我不同意。驗證對象機制應該在領域類別之外進行描述,這一點毫無疑問。但爲了始終保持一個對象處於內聚狀態,特別是防止有人在事先不使用「外部」工廠的情況下創建它,必須在創建它之前驗證它,因此驗證應該通過域類來調用。我特別爲不可改變的階級而思考。 – Mik378 2013-05-05 20:43:53

+1

我相信這裏的一個好方法是使用Fluent Builder模式。這樣,Car類本身可以不可變,Car.Builder類將包含所有必要的驗證規則。 – Olaf 2013-05-07 20:46:15

+0

@Olaf是的,但這並不能解決問題。您的解決方案的後果:違反SRP。如果我們想要解決SRP問題,即使有一位漂亮流利的建築師,我們也會在帖子中回到我的問題。 – Mik378 2013-05-08 13:17:51