ddd - 我的ValueObject实现是否正确?

时间:2016-06-08 15:20:33

标签: domain-driven-design value-objects

我正在尽我所能创建一个Web应用程序来熟悉DDD和ValueObjects。到目前为止一切正常,我只是问自己我是否正确实现了我的值对象。这是我当前的状态(从非必要部分剥离的代码):

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类中吗?

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

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

这是正确的想法。

在此实现中,$ username和$ password是Credentials状态的一部分。你希望那个状态是不可变的;在构造函数完成后,应该没有更改该状态的代码。

然而,你需要以某种方式暴露这种状态;不可变的只写对象不提供非常大的业务价值。将值类型实现为不可变公共属性的集合是一种常见的习惯用法。 Here's关于如何在PHP中执行此操作的旧讨论。或者,您可以实现允许Credentials对象将该状态的副本传递给其他对象的调用。

  

我应该为User类的$ credentials属性创建一个getter和setter吗?

通常不会 - 您的User实现具有Id属性,这使其看起来像一个实体。实体很少允许其内部状态逃脱。特别是,setter是很多9个,从来都不是一个好主意 - 实体的意思是它们可以强制执行自己的数据约束;他们有责任确保所有状态的变化都能满足业务不变性。

提供访问不可变状态的getter不太可能导致问题;允许调用者导航到可变状态的getter是令人担忧的。

但是: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)方法。

答案 1 :(得分:0)

几乎我会说。值对象的关键是它是一个值。即您可以将它与另一个相同类型的对象进行比较,并确定它的值是否不同。在这种情况下,我希望能够看到一个凭证,其中username = x和password = x将“等于”另一个具有相同值的凭证。

这并不一定意味着你需要在田野上吸气。

我的博客上有关于这个主题的有趣代码kata。你可以在Why Private C# Variables are Not as Private as you Thought

找到它

价值对象kata靠近底部。希望有所帮助。