2012-03-05 58 views
0

在我們的系統中,我們有一個實體Product,它可能具有各種自定義屬性。一組屬性可能因產品而異,存儲在List<Property>類型的字段中。屬性具有不同的類型(字符串,整數,雙精度),並且可能有一些特殊的特徵,例如它們可能是多值的,可能是s特定範圍的值,來自給定列表的值等。屬性的值總是包含在字符串字段Value中。驗證錯誤層次設計

現在我目前的問題是實現這些屬性的驗證,我堅持採用什麼方法來取得部分驗證結果的陳述。我必須滿足的要求: - 驗證結果將被其他應用程序層使用,因此生成的API應該清晰易用 - 每個錯誤應該有不同的表示形式 - API的用戶應該有足夠的空間信息瞭解錯誤細節(例如用於範圍錯誤,他們應該提供最小的可能值,最大可能值和實際值)

下面是到目前爲止,我已經考慮方法:

  1. 類層次結構。有一個基本的抽象類ValidationError,每個特定的錯誤都會反映在一個繼承的類中。如果錯誤有任何具體細節,相應的類將有必要的字段來存儲所有的信息。例如:

    public abstract class ValidationError 
    { 
        // common fields and methods, if any 
    } 
    
    public class IncorrectFormatValidationError : ValidationError 
    { 
        // just empty class, nothing to add here 
    } 
    
    public class RangeValidationError : ValidationError 
    { 
        public object MinValue { get; set; } 
    
        public object MaxValue { get; set; } 
    } 
    

    這種做法似乎是因爲各種實際空類的,而多餘的我。此外使用這樣的API似乎並不正確(if (typeof(error) == typeof(RangeValidationError)) - 廢話!)。然而,這是我首先想到的。

  2. 錯誤枚舉以及必要時的類層次結構。所有錯誤都以枚舉表示。在大多數情況下有一個類爲ValidationError,並且當對於特定錯誤需要附加信息時,繼承者被創建,基本上與第一種方法相同。例如:

    public enum ValidationErrors 
    { 
        IncorrectFormat, 
        ValueNotWithinRange, 
        ... 
    } 
    
    public class ValidationError 
    { 
        public ValidationErrors ErrorType { get; set; } 
    
        public ValidationError(ValidationErrors type) 
        { 
         this.ErrorType = type; 
         ... 
        } 
    
        // common fields and methods, if any 
    } 
    
    public class RangeValidationError : ValidationError 
    { 
        public object MinValue { get; set; } 
    
        public object MaxValue { get; set; } 
    
        public RangeValidationError(object minValue, object maxValue) : 
         base(ValidationErrors.ValueNotWithinRange) 
        { 
         ... 
        } 
    } 
    

    這種方法看起來好多了,但也有缺點。最大的一個問題是,我們作爲API用戶不能保證當我們有類型說ValueNotWithinRange的錯誤時,我們正在處理RangeValidationError類的類,如果我們不是 - 我們如何處理它?我希望有一些設計級別的功能可以防止這種情況發生,因爲我不是開發API的onyl開發人員。這種方法的另一個問題是,如果大多數錯誤到底會需要一些額外的信息,我們最終會以相同的aprroach數1

任何人有任何想法就這兩種方式或共享結束建議一個更好的?我將非常感謝任何迴應。提前致謝。

回答

0

這可能是退一步,重新考慮整個「多類代表驗證錯誤」的做法是一個好主意,因爲它幾乎可以保證你已經擁有的驗證一個層次。

可以完美指定給任何驗證錯誤:

  1. 未能接受財產
  2. 財產
  3. 值的名稱失敗的值的驗證,驗證

任何進一步的信息(例如範圍的限制,不匹配的正則表達式)已經存在於驗證器實例中,並且可以通過它進行訪問。

所以大約有隻有一個驗證錯誤類,看起來像這樣的內容:

public sealed class ValidationError 
{ 
    public Validator Validator { get; set; } 
    public string PropertyName { get; set; } 
    public object AttemptedValue { get; set; } 
} 
+0

事實上,您可以通過這種方式避免層次結構重複,但您也會引入額外的向下呈現的抽象驗證器。我建議將Validator更改爲類型參數。 – Basilevs 2012-03-05 09:52:27

+0

@Basilevs:如果您需要訪問層次結構根目錄中不存在的成員(例如'Min'和'Max'屬性),則無論如何都需要向下轉換(即使在「ValidationError」層次結構中)。唯一的另一種方法是構建一個在運行時動態訪問屬性值的設施,這是使用反射的道德等價物,具有相同的基本問題:類型安全性的損失。 – Jon 2012-03-05 09:56:23

+0

@Jon,感謝您的回覆。不,我目前沒有驗證器。所有的驗證都在幾個BL級別的方法中完成。不過也許值得考慮一下他們的介紹?但是,如果是這樣,我們面臨着與錯誤相同的問題(這是在問題中描述的),不是嗎? – Andrei 2012-03-05 11:34:24

0

你可能想看看像FluentValidation。它輕巧,直觀,涵蓋了很多驗證場景。

如果您對FluentValidation使用的驗證結果不滿意,則可以將它們包裝在您自己的自定義驗證錯誤類中。至少你會得到很多免費的基本功能。