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

时间:2014-09-18 11:13:20

标签: php entity domain-driven-design coupling value-objects

我的User实体值对象松散耦合,因此我使用UserFactory来构建对象,无论何时来自数据库或创建一个全新的实体到域名。

是否可以将值对象紧密耦合,以便在更新实体的属性时,我可以摆脱其工厂并使我的应用程序服务膨胀与单个值对象实例化逻辑(在能够注入它们之前)? Aren不会重视与根密切相关的对象吗?

例如,当我使用松耦合版本更新其中一个属性时,我必须首先实例化值对象,然后然后注入它。但在紧密耦合的示例中,我可以直接输入新值,而无需明确地完成实例化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.
}

1 个答案:

答案 0 :(得分:2)

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

使用复杂的值对象表明它不是" setter"建立一个价值对象的责任,因为设置日期需要区域设置(或者让我们设想其他值 - 仅用于演示)而不仅仅是日期的字符串值。所以传递日期作为值对象更有意义和更清楚地展示意图。

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并创建" complex"您可以创建辅助(工厂)方法或工厂的值对象取决于它的复杂程度:

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));