У меня есть мой User
объекты значения сущности слабо связаны, и из-за этого я использую UserFactory
создавать объект всякий раз, когда он поступает из базы данных или при создании совершенно нового объекта в домене.
Разве можно было бы плотно связать объекты-значения, чтобы я мог избавиться от его Фабрики, а мои службы приложений были бы раздуты с помощью индивидуальной логики создания объекта-значения (до того, как можно было внедрить их) при обновлении сущности и ее свойств? Разве объекты значения не имеют тесной связи с их корнем?
Например, когда я обновляю одно из свойств со слабосвязанной версией, мне сначала нужно будет создать экземпляр объекта значения, и затем впрысните это. Но в тесно связанном примере я мог бы просто вводить новые значения напрямую, без необходимости явно проходить процесс создания экземпляров 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.
}
Я думаю, что пример очень упрощенный и не показывает истинную степень проблемы / вопроса. Я пытаюсь добавить больше сценариев, которые лучше продемонстрируют разницу между «слабо» & «тесно» связанные решения.
Использование сложного объекта-значения показывает, что создание объекта-значения не является обязанностью «установщика», поскольку для установки даты вам нужен языковой стандарт (или давайте представим другие значения — просто для демонстрации), а не только строковое значение даты. Таким образом, передача даты в качестве объекта значения имеет больше смысла и более четко демонстрирует намерение.
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, вам нужно будет добавить другой метод. В следующем примере вы можете видеть, что установщик должен принимать только объект Value, а для создания «сложных» объектов Value вы можете создать вспомогательный (фабричный) метод или 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));
Других решений пока нет …