Сутність має ідентичність, що зберігається протягом усього життя: користувач лишається тим самим користувачем, навіть якщо змінив ім'я, email і адресу. Дві сутності з однаковими полями, але різними id - різні об'єкти.
Об'єкт-значення не має ідентичності - він визначається лише своїми значеннями. Дві суми «100 гривень» - одна й та сама сума; немає сенсу питати «яка саме з них».
| Сутність | Об'єкт-значення | |
|---|---|---|
| рівність | за ідентифікатором | за всіма значеннями |
| зміна | змінюється з часом | незмінний: «зміна» = новий об'єкт |
| приклади | User, Order, Invoice |
Money, Email, Address, DateRange |
Об'єкт-значення в PHP:
final readonly class Money
{
public function __construct(
public int $amount, // у копійках
public string $currency,
) {
if ($amount < 0) {
throw new InvalidArgumentException('Сума не може бути від\'ємною');
}
}
public function add(Money $other): self
{
if ($other->currency !== $this->currency) {
throw new InvalidArgumentException('Різні валюти');
}
return new self($this->amount + $other->amount, $this->currency);
}
public function equals(Money $other): bool
{
return $this->amount === $other->amount && $this->currency === $other->currency;
}
}
Що дають об'єкти-значення:
- валідація в одному місці: некоректний
Emailчи від'ємну суму неможливо створити - не треба перевіряти скрізь, де вони використовуються; - поведінка поруч з даними: додавання грошей, перевірка перетину періодів;
- незмінність (
readonly) - об'єкт можна безпечно передавати й кешувати; - виразність:
function charge(Money $amount)замістьfunction charge(int $amount, string $currency).
У Laravel об'єкти-значення зберігають у моделях через власні касти (CastsAttributes): Money з двох колонок price_amount і price_currency.
Пастка: робити сутністю те, що насправді значення (окрема таблиця addresses з id для адреси, яка ніколи не існує окремо від замовлення), - і навпаки.