2013-07-12 40 views
0

我有一個PHP MVC應用程序,我的'M'有一個服務層,映射器層和域層。在哪裏以及如何檢查以確保對象具有所有必需的屬性?在哪裏檢查域對象中的強制屬性?

在我看來,這些責任不屬於映射器或服務層,因此離開域本身。我在我的基礎域類中放了一個方法,checkRequired()。它根據$_required屬性數組檢查對象的屬性,如果缺少任何屬性,則會引發錯誤。

當從數據庫中檢索對象時,我一直呼叫checkRequired()作爲對象構造函數中的最後一個命令。如果對象是一個新的實體(即不從數據庫中檢索),我提供一些默認值(在構造函數中),然後調用checkRequired()

雖然這一直行得通,但我現在將一些行爲方法放在我的(有點貧血的)域對象上,並且我遇到了麻煩。例如,用戶可以擁有許多寵物,所以在我的用戶模型中,我使用了addPet()方法。我知道我需要傳入Pet對象,因爲最好注入依賴關係,因此我的真實方法簽名是User::addPet(ConcretePet)

但這就是問題所在!我的寵物不能存在沒有用戶(作爲他們的所有者),所以我不能實例化ConcretePet!我可以讓用戶在寵物上可選,但這將是一個落後的步驟。我可以將checkRequired()的內容移到其他地方,但是在哪裏?

解決這種常見問題的典型方法是什麼?

+1

看來,如果一個寵物需要有一個用戶,那麼用戶應該被傳遞到ConcretePet的構造函數 – Orangepill

+0

或者你可以在用戶上創建一個工廠方法來創建一個ConcretePet – Orangepill

+1

我不會回答你的問題(它已經回答了)而是對checkRequired()方法進行評論。這種明確的檢查方法不應該是你的API的一部分,可能隱藏在你的聚合根中。您的構造函數應該足以爲清潔實體實例化(並檢查不變量)提供數據。如果不是,請使用Factory。 – gseric

回答

1

該checkRequired不是DDD的方式。一個實體應始終有效。換句話說 - 你不應該有辦法把它置於無效狀態(比如缺少屬性)。怎麼樣? 當您剛剛設置了公共屬性時,這是貧血症。您在數據庫中保留的屬性應該是私有的。設置它們的唯一方法是通過具有商業含義的方法。這些方法應該檢查所有的不變量(不只是必填字段 - 所有種類的限制,這將使實體合法與否),並防止更新,如果他們中的一些沒有得到滿足。

關於用戶 - >寵物話題:如果寵物離不開用戶存在,則可能是用戶是一個聚合根,負責保護有關用戶和寵物不變。這意味着應該有一個方法addPet ...呃...也許更有意義的東西?採用寵物和寵物寵物(他們可能會有稍微不同的規則和輸入)?這採用寵物應確保有一個用戶的寵物的不變...順便說一句 - 爲什麼用戶而不是所有者?

但寵物也可以是一個聚合根。這意味着它的構造函數應該需要用戶參數。

注意,這取決於從使用的情況下什麼是聚合根。在某些情況下,Pet被視爲聚合根,但在採用寵物的情況下,它是User聚合的一部分。

0

盡你所能建立一種單向關係。如果可以單獨跟蹤寵物(我的意思是沒有用戶),請將其視爲聚合根。

在Pet中放置一個User屬性,但在User中沒有寵物屬性。因此,您不需要在用戶中使用addPet()方法。

如果你想找到屬於用戶所有的寵物,而是使用一個查詢:

public class PetRepository { 
    public List<Pet> findByOwner(String uid) { 
     //omitted codes 
    } 
} 

希望這有助於。

0

當從數據庫中檢索對象時,我一直呼叫 checkRequired()作爲對象構造函數中的最後一個命令。

偏離主題,但這可能會有問題。假設所需的一組屬性在某個時刻發生了變化,使得持久實體不再有效。你仍然希望能夠重建它們,所以你不應該在重建時進行檢查。相反,只能在創建時或行爲期間運行驗證。

至於所述addPet方法,而不是傳遞一個具體的寵物類的一個實例,通過創建一個寵物的方法參數或作爲PetInfo類的一個實例的實例所需的數據。這將允許User類創建一個完全有效的實例Pet