通过紧密耦合实体工厂的值对象来摆脱实体工厂



我的User实体值对象松散耦合,因此,每当对象来自数据库或在域中创建全新实体时,我都会使用UserFactory来构建对象。

在更新实体的属性时,可以将值对象紧密耦合,这样我就可以摆脱它的工厂,并让我的应用程序服务充斥着单个值对象实例化逻辑(在能够注入它们之前)吗?值对象不是和它们的根紧密相关吗?

例如,当我用松散耦合的版本更新其中一个属性时,我必须首先实例化value对象,然后注入它。但在紧密耦合的示例中,我可以直接输入新值,而不必显式地完成实例化VO的过程。

示例:

// Updating User's name (loosely coupled version)
$firstName = new FirstName('John');
$lastName  = new LastName('Doe');
$fullName  = new FullName($firstName, $lastName);
$user->setFullName($fullName);
// Updating User's name (tightly coupled version)
$user->setFullName('John', 'Doe');

松散耦合:

class User extends Entity
{
    private $fullName;
    private $email;
    public function getFullName()
    {
        return $this->fullName;
    }
    public function setFullName(FullName $fullName)
    {
        $this->fullName = $fullName;
        return $this;
    }
    public function getEmail()
    {
        return (string) $this->email;
    }
    public function setEmail(Email $email)
    {
        $this->email = $email;
        return $this;
    }
    // etc.
}

紧密耦合:

class User extends Entity
{
    private $fullName;
    private $email;
    public function getFullName()
    {
        return $this->fullName;
    }
    public function setFullName($firstName, $lastName)
    {
        $firstName      = new FirstName($firstName);
        $lastName       = new LastName($lastName);
        $this->fullName = new FullName($firstName, $lastName);
        return $this;
    }
    public function getEmail()
    {
        return (string) $this->email;
    }
    public function setEmail($email)
    {
        $this->email = new Email($email);
        return $this;
    }
    // etc.
}

我认为这个例子非常简单,没有显示问题的真实程度。我尝试添加更多的场景,以更好地展示"松散"和;"紧密"耦合的解决方案。

使用复杂的Value Object表明,构建Value Object不是"setter"的责任,因为为了设置日期,您需要区域设置(或者让我们想象一下其他值——只是为了演示),而不仅仅是日期的字符串值。因此,将日期作为Value Object传递会更有意义,更清楚地表明意图。

class User extends Entity
{
    private $dateOfBirth;
    public function setDateOfBirth(Zend_Date $date)
    {
        $this->dateOfBirth= $date;
    }
    public function setDateOfBirth2($date = null, $part = null, $locale = null)
    {
        $date = new Zend_Date($date, $part, $locale);
        $this->dateOfBirth = $date;
    }
}

正如您所看到的,方法User::setDateOfBirth2()看起来并不正确——它有两个责任,因此破坏了SRP。如果需要使用Zend_date对象设置日期,则必须添加另一个方法。在下一个例子中,您可以看到setter应该只接受Value Object,对于"复杂"Value Object的创建,您可以创建一个helper(工厂)方法或factory-这取决于它的复杂程度:

class User extends Entity
{
    private $dateOfBirth;
    public function setDateOfBirth(Zend_Date $date)
    {
        $this->date = $date;
    }
    public function createDate($date = null, $part = null, $locale = null)
    {
        return new Zend_Date($date, $part, $locale);
    }
}
$user = new User;
$user->setDateOfBirth($dateOfBirth);
// or
$user->setDateOfBirth($user->createDate($date, $part, $locale));

相关内容

  • 没有找到相关文章

最新更新