2016-06-08 99 views
0

我正在盡我所能來創建一個Web應用程序來熟悉DDD和ValueObjects。到目前爲止,一切工作正常,我只是問自己,如果我正確實施我的價值對象。這是我目前的狀態(代碼非必要的部分剝離):ddd - 我的ValueObject實現是否正確?

class User { 

    private $id; 

    /** 
    * @var Credentials 
    */ 
    public $credentials; 

    public function getId() { return $this->id; } 

} 

class Credentials { 

    private $username; 
    private $password; 

    public function __construct($username, $password) { // no need to detail } 

    public function changePassword($newPassword) { 
     return new self($this->username, $newPassword); 
    } 
} 

所以每當我想更新我的用戶的密碼,我要做$user->credentials = $user->credentials->changePassword("newPassword");

這是正確的嗎?我應該爲我的User類的$credentials屬性創建一個getter和setter?我應該將changePassword()方法放在User類中嗎?

任何幫助,非常感謝!

回答

3
$user->credentials = $user->credentials->changePassword("newPassword"); 

這是正確的想法。

在這個實現中,$ username和$ password是Credentials狀態的一部分。你希望這個狀態是不變的;應該沒有代碼在構造函數完成後改變該狀態。

但是,您需要以某種方式公開該狀態;不可變的只寫對象不提供非常多的商業價值。將值類型實現爲不可變公共屬性集合是一種常見的習慣用法。 Here's關於如何在PHP中執行此操作的舊討論。或者,您可以實施調用,以允許憑證對象將該狀態的副本傳遞給其他對象。

我應該爲我的User類的$ credentials屬性創建一個getter和setter?

通常不會 - 您的用戶實現具有Id屬性,這使得它看起來像一個實體。實體很少讓他們的內部狀態逃脫。特別是,setters有很多九個接近絕不是一個好主意 - 實體的一點是他們可以強制自己的數據約束;他們有責任確保對其狀態的所有更改滿足業務不變。

提供訪問不可變狀態的getter不可能導致問題;允許呼叫者導航到可變狀態的吸氣劑令人擔憂。

但是:干將不是特別表現 - 查詢,可能是由域服務支持,往往是一種更靈活的選擇

比較:

password = user.password 
strength = calulatatePasswordStrength(password.toString) 

password = user.password 
strength = password.strength(calculator) 

strength = user.passwordStrength(calculator) 

我應該把changePassword()方法放在User類中嗎?

假設您支持該用例,是的。憑證值知道如何計算舊憑證的新狀態;用戶實體知道如何驗證以當前狀態的用戶被允許以這種方式更改憑證。 (例如:一個天真的安全實現可能會跟蹤上次更改憑證的時間,並且具有限制密碼更改的策略,其中使用的正確策略取決於用戶的其他屬性。對於憑證來說,這樣做太多了。對象自己做。)

特別是,用戶的密碼實際上是Credentials值對象中的一堆狀態的事實是一個實現細節,它不應該暴露給調用User的代碼。換句話說,如果用戶正在實現接口IUser(隔離實現細節),那麼我希望IUser承諾changePassword($ password)方法將可用。

+0

好吧,現在看來我更清楚了。我將在我的User類中創建一個changePassword()方法,然後使該屬性保持私有狀態,這將使代碼更加美觀,易於閱讀。非常感謝 ! – Lucio

0

差不多我會說。值對象的關鍵是它是一個值。即您可以將其與另一個相同類型的對象進行比較,並可以根據其值確定它是否不同。在這種情況下,我希望能夠看到其中username = x和password = x的Credential將'等於'具有相同值的另一個憑證。

這並不一定意味着你需要在領域的getters。

我在我的博客上有這個主題的有趣代碼kata。你可以在這裏找到它Why Private C# Variables are Not as Private as you Thought

值對象kata接近底部。希望有所幫助。

+0

我看看你的卡塔,沒有問題。事實是,當一個ValueObject在一個實體內部時,我需要訪問它。我有習慣爲所有事情創建getter/setter,並且我試圖失去它。然而,執行'$ user-> changePassword($ password)'似乎比'$ user-> credentials = $ user-> credentials-> changePassword($ password)'容易# – Lucio

+0

您是否需要憑證對象所有在這種情況下?它會有更多的功能嗎? – Codescribler

+0

其實我不認爲,現在其實不是。我以爲我會放一個'$ email'屬性,但它不適合它,因爲它更像是我的項目中的「屬性」屬性。 – Lucio