Reputation: 1337
I have 1 Employee
entity which holds a value object of ContactInformation
:
Employee.php
class Employee {
private $contactInformation;
public function __construct(ContactInformation $contactInformation) {
$this->contactInformation = $contactInformation;
}
public function getContactInformation() {
return $this->contactInformation;
}
}
ContactInformation.php
class ContactInformation {
private $email; // Required
private $cellPhone; // Required
private $phone; // Optional
private $address; // Optional
public function __construct($email, $cellPhone) {
$this->email = $email;
$this->cellphone = $cellphone;
}
/** Here goes a bunch of setter getter for those properties **/
}
If an Employee's phone is changed, is it not better to do just
$employee->getContactInformation()->setPhone($newPhone)
Rather than forcing immutability such as
$employee->setContactInformation(new ContactInformation(/** copy paste here **/));
Going by Eric Evans' book, I understand that when you change a part of a value object, then it is a whole different value object then it was before.
I just cannot get the same conclusion about a little bit more complex object like this ContactInformation, is it supposed to be an Entity?
Need advice, thanks !
Upvotes: 1
Views: 110
Reputation: 48883
Interesting discussion. What I do is to have getContactInformation return a clone.
class Employee {
public function getContactInformation() {
return clone $this->contactInformation;
}
...
$contactInformation = $employee->getContactInformation();
$contactInformation->setPhone('');
$employee->setContactInformation($contactInformation);
By doing so, the value object actually stored inside of Employee is immutable. You always pull a copy, which since it no longer linked to employee, is no longer a value object(one could argue with lots of hand waving) and thus can be modified without upsetting the DDD police.
Works for me and let's me use a form system which expects setters.
Upvotes: 1
Reputation: 7034
For me, Employee to have dependency on ContactInformation
means that you expect to have ContactInformation
already set with phones, etc. and then passed to employee, i.e.:
$contanctInfo = new ContactInformation();
$contanctInfo->setPhone(820);
$employee1 = new Employee($contanctInfo);
echo $employee1->getContanctInformation()->getPhone(); // 820
However, that means you would need to make as much ContactInformation objects, as Employee objects, before instantiating each Employee, because:
$contanctInfo = new ContactInformation();
$contanctInfo->setPhone(820);
$employee1 = new Employee($contanctInfo);
$employee2 = new Employee($contanctInfo);
$employee1->getContactInformation()->setPhone(123);
$employee2->getContactInformation()->setPhone(666);
echo $employee1->getContactInformation()->getPhone();
echo $employee2->getContactInformation()->getPhone();
Turns into:
666
666
Because you are changing one and the same object.
In your case, you are instantiating ContactInformation
at the same time, when you are instantiating Employee
when makes the dependency a bit useless:
$employee1 = new Employee(new ContactInformation());
$employee2 = new Employee(new ContactInformation());
$employee1->getContactInformation()->setPhone(123);
$employee2->getContactInformation()->setPhone(666);
echo $employee1->getContactInformation()->getPhone();
echo $employee2->getContactInformation()->getPhone();
Results into:
123
666
So, if you don't want to make changes on the dependent object before inject it to another object, you don't need a dependency at all. Even more, in real world ContanctInformation
is bind to an Employee
, not the opposite.
I would make it this way:
class Employee {
private $_contactInformation;
public function __construct() {
$this->_contactInformation = new ContactInformation($this);
}
/**
* @return ContactInformation
*/
public function getContactInformation() {
return $this->_contactInformation;
}
}
class ContactInformation {
private $_employee;
private $email; // Required
private $cellPhone; // Required
private $phone; // Optional
private $address; // Optional
public function __construct(Employee $employee) {
$this->_employee = $employee;
}
public function setPhone($phone) {
$this->phone = $phone;
}
public function getPhone() {
return $this->phone;
}
}
$employee1 = new Employee();
$employee2 = new Employee();
$employee1->getContactInformation()->setPhone(123);
$employee2->getContanctInformation()->setPhone(666);
echo $employee1->getContactInformation()->getPhone();
echo $employee2->getContactInformation()->getPhone();
On the other hand, if Employee has some identificator, so the ContanctInfo
retrieves info based on the ID, you can make the injection the way you want it.
Upvotes: 1
Reputation: 2454
Value objects should be immutable, but ContactInformation
should not be a value object.
Consider two people who share a house, and therefore have the same address and phone number (it simplifies matters if you assume they don't have a cellular phone or email).
In that situation, they'd have identical ContactInformation
objects, but the contact information is still distinctly one person's or another's. If one of them moves out, or buys a cell phone then their contact information will have to change.
As you mentioned in your comment, it's better to consider ContactInformation
as a mutable Entity, and not a Value Object.
Upvotes: 1