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