2010-04-09 23 views
15

我已經閱讀了關於OOP DDD/PoEAA /四人幫的幾本書,它們都沒有涉及驗證的主題 - 它似乎總是假定數據是有效的。面向對象設計 - 何處/何時驗證屬性?

我從這篇文章的答案(OOP Design Question - Validating properties)中收集到一個客戶端應該只嘗試在域對象上設置有效屬性值。

此人已經問過類似的疑問,仍然沒有答案:http://bytes.com/topic/php/answers/789086-php-oop-setters-getters-data-validation#post3136182

那麼,你如何確保它是有效的? 你有沒有一個「驗證方法」,每個吸氣和吸氣器?

  • isValidName()
  • 的setName()
  • 的getName()

我似乎缺少有關OOP數據驗證的一些關鍵基礎知識 - 你可以點我一本書,封面這個話題詳細? - 即。覆蓋不同類型的驗證/不變量/處理反饋/使用例外或不等

+1

我想補充的是,經過一些調查研究,我發現這個有用:http://devcity.net/Articles/381/1/article.aspx – 2010-04-09 22:08:10

回答

7

根據我的經驗,驗證發生在有人類/用戶輸入的地方。這通常發生在你允許通過你的方法改變某些東西的地方。在你的榜樣,我會去驗證的方法:

setName() 

所以它發生在那裏你允許值的輸入/設定值,其結果是setter方法。

1

每個對象都應該確保它的內部狀態是一致的,所以驗證最好在內部狀態被修改之前完成 - 在對象的setter方法中。

1

總之,總是驗證。總之,一次完成所有的驗證,而不是「一路走來」。這將幫助您的代碼保持精簡併幫助調試混淆。

1

如果您控制使用您的類的代碼,那麼您應該在嘗試操作對象的變量(通過公共屬性)之前進行驗證。如果你正在預測一個你不知道你的班級將如何使用的場景,那麼是的,你應該在該場所內進行驗證,這或多或少是他們的目的。顯然這假定「是一個有效的名稱」的定義是該對象固有的靜態商業規則。

驗證這兩個級別當然是最安全的路線。

+0

是的「的isValid」的定義是相當一個令人困惑的領域。這個問題似乎需要爲了可靠一些背景 - 我發現自己寫的東西,如:命令中─> IsValidOrderAccordingToPaymentStrategy() 希望聽到經典的一本書對這個話題,每個人,但我似乎已經閱讀。 – 2010-04-09 19:15:57

+0

在多個地方驗證似乎是個不錯的主意。首先,你有重複的代碼來維護。此外,從概念上講,如果你有一個牛的對象,牛應該知道什麼是有效的食物投入 - 你不希望世界上的每一個植物都證實自己是可以接受的牛食品。讓牛決定。 – 2010-04-09 19:17:01

+0

但你不一定要把你的牛放到充滿有毒蘑菇的牧場上,即使合理確定你的牛不會吃它們。 :) – sweaver2112 2010-04-09 20:14:01

1

OOP的一個重要組成部分始終保持您的對象處於有效狀態。因此,應該在可以修改對象的輸入之後進行驗證。

驗證從屬性/集合,參數到函數和構造函數的數據是很好的。

+0

「OOP的一個重要部分是始終保持您的對象在一個有效的狀態」 - 我喜歡這個,謝謝。 – Jimbo 2014-11-28 13:24:13

3

區分域對象的不變量(必須始終滿足)和有人稱之爲「contextual validation."例如,具有負面銀行帳戶的客戶是否無效」這一點非常重要?「否,但是他們可能無權執行某些類型的交易。這是上下文驗證,與「每個客戶實體必須具有非空ID」相反,這是完全不同類型的驗證。執行不變量

一種有效的方法是在域對象區分表示域對象的用戶輸入,並且不暴露無限制增變器(組簡單的存取,例如)類。

舉例來說,如果你有一個Student域對象,不直接在用戶界面中進行操作。您的視圖不會創建Student實例,而是創建StudentBuilder實例,這些實例將模擬構建有效的域對象所需的內容。

接下來,你有驗證建設者實例符合域對象的不變量類,和工廠是需要接受的建設者和可以將其轉化爲有效的域對象。 (您也可以在此步驟中適當引入上下文驗證策略。)

+0

是的,這似乎是有道理的。我通過創建一個'規範對象'或'數據籠'來容納傳入數據來做到這一點 - 但之前並不確定。 – 2010-04-09 19:32:17

1

這取決於你的編程風格,維基百科有更詳細的解釋,我將只是劃傷表面,並鏈接到維基百科。 (是的,我懶:-))。

注:所有這一切並不適用於用戶輸入。你必須以任何方式驗證它。我只是談論業務邏輯類,它不應該以任何方式與用戶輸入相結合。 :-)

  • 防守

正如其他人所說,你將執行每個屬性的邊界。我經常拋出運行時異常(Java)來表明這些失敗。

Wikipedia on Defensive Programming

  • 通過合同

您記錄您的代碼的要求和承擔,例如,傳遞給你制定者的值是有效的關於所定義的合同。這爲您節省了很多樣板代碼。但是當發現非法價值時,尋找錯誤將會更加困難。

Wikipedia on Design by Contract

+0

我發現Design By Contract(TM)信息非常有用 - 特別是'失敗'的想法,這似乎是所有這些答案的運行主題。讓供應商的工作儘可能簡單,並讓客戶決定在價值被拒絕時應該怎麼做。 – 2010-04-09 20:59:53