Комментарии 49
Собственно в статье оно и приводится, потому как это самые настоящие объекты-значения. Вот только VO не обязательно должны быть имутабельными, во всяком случае это только рекомендуется. Так же могут быть коллизии с другой литературой, где под VO подразумеваются DTO.
Ни слова о VO в статье нет потому что статья не про VO, а про неизменяемость в целом.
Александр написал ровно то что я хотел, так что в чем суть притензии. Если что продублирую.
VO — это более общий термин, он не про имутабельность, он про идентичность объектов по значению. То что их можно делать имутабельными — это вот к теме статьи, и статья прекрасно раскрывает зачем это нужно.
Думаю в качестве примера использования «неизменяемых объектов» прекрасно подошел бы шаблон «Value Object» Фаулера
Перечитайте еще пару раз.
Он там и есть в примере. Просто не написано «это VO».
От того, что VO тоже должны быть неизменяемыми, не значит, что они тоже есть в примерах, поверьте.
VO не должны быть неизменяемыми, они могут таковыми быть и желательно что бы они таковыми были, но имутабельность это отдельный вопрос.
Ну и из ваших слов не понятно. то есть вы признаете реализацию паттерна только если рядом напишут название? Как-то это глупо.
В целом вы придираетесь к названиям, хотя это не важно. Суть в статье передана верно, в чем притензия?
Ну и из ваших слов не понятно. то есть вы признаете реализацию паттерна только если рядом напишут название? Как-то это глупо
В целом вы придираетесь к названиям, хотя это не важна. Суть в статье передана верно, в чем притензия?
Я не буду против, если вы назовете пример, при чтении которого у читателя не возникнет вопроса «зачем» хотя бы трамваем, мне все равно. Говорю о VO я здесь по двум причинам:
1. Прекрасно подходит в качестве примера
2. Все его знают (я надеюсь)
Боюсь вы размышляете не о том, о чем говорю я.
Прекрасно подходит в качестве примера
Первый же пример с Address
. Просто в статье не говорится о том что это value object, а просто объект. Что более чем просто понятно и не нагружает мозг читателя лишними терминами.
- Все его знают (я надеюсь)
знаете, вот из общения с PHP разработчиками — далеко не все. А многие под VO подразумевают только DTO. Да и Эванса многие не читали и используют active record с публичными пропертями. А еще есть приличный процент тех кто используют массивчики и глобальное состояние в сингелтонах.
Просто в статье не говорится о том что это value object
А ведь как было бы здорово, если бы говорилось.
у читателя не возникнет вопроса «зачем»
Что более чем просто понятно и не нагружает мозг читателя лишними терминами
Все его знают (я надеюсь)
знаете, вот из общения с PHP разработчиками — далеко не все
Вот с этого и надо было начинать, а то вас куда то не в ту глуш увело.
Вот с этого и надо было начинать, а то вас куда то не в ту глуш увело.
нет, вы зациклились на том что бы в статье упоминалось VO. Я пытался объяснить что статья НЕ про VO, хотя темы пересекаются. А дальше пошла рекурсия.
Перечитайте еще пару раз.
вы тоже перечитайте еще пару раз. Пример с Address это классический VO. Просто сам термин VO имеет несколько значений в зависимости от контекста. Да, интерпритация Фаулера и Эванса популярна, но это не подавляющее большинство. Да и зачем усложнять то? Если у вас объект имутабельный — он автоматически становится VO как бы мы не крутили.
он автоматически становится VO как бы мы не крутили
VO это цель, «неизменяемые объекты» это средство. В качестве примера лучше подойдут решения имеющие цель, а не средство. Когда читатель, не знакомый с этими решениями прочитает подобную статью, у него сразу же возникнет вопрос «зачем», а VO один из прекрасных примеров, позволяющих ответить на этот вопрос.
VO это тоже не цель — это просто средство.
Конкретно в этой статье речь только про имутабельноть и как это важно для борьбы с сайд эффектами. VO это более обширная тема и имутабельность это не только их характеристика.
Это бесполезный спор. Хотите — напишите статью про VO.
Если у вас объект имутабельный — он автоматически становится VO как бы мы не крутили.
Нет. Определяющая характеристика VO — сравнение по значению всех полей, а не по идентифицирующим. Пример — объект финансовой транзакции по какой-то сущности. Иммутабельный (чёрную бухгалтерию не рассматриваем), изменение баланса сущности производится выравнивающими/сторнирующими транзакциями, но обладающий чёткой идентичностью — даже если все значимые значения (суммы, даты с точностью до наносекунд, контрагенты и т. п.) равны, то всё равно каждая транзакция обладает собственной идентичностью. С другой стороны, иммутабельность не является даже необходимым признаком VO. Это лишь рекомендуемая характеристика для избежания необходимости отслеживания побочных эффектов.
Все примеры работают на PHP 7.
Можно, но смысл от этого не поменяется. В следующих статьях предложу это Марку.
использовать типизацию
вы имели в виду тайп хинтинг для скаляров? Можно, но это излишнее усложнение.
return types и т.д.
опять же можно, но в половине примеров это бесполезно без дженериков и nullable types (последние появятся только в 7.1)
На мой взгляд для полноты примера было бы полезно описать код Money::USD()
.
И Money::val()
. Он чем-то отличается от Money::getAmount()
?
Это вопервых не статические методы, а во вторых либо имеет место опечатка, либо оно и в правду одно и то же.
Это принятое обозначение, чтобы сослаться на метод класса, не важно статический он или нет, вот например, тут так делают. Или я совсем туплю под вечер? :)
это просто статический метод-фабрика. Именованный конструктор если хотите. Тут не так давно перевод поста Матиаса Верраеса проскакивала на эту тему.
Суть-то понятна, но код этого метода — 1 строка, не обязательно на ней было экономить
public static function USD($val) {
return new static($val, static::CURRENCY_USD);
}
Если класс final — то точно не нужно, а так не вижу проблемы. Если вы их видите — предлагаю обсудить, мне будет полезно.
final наследовать нельзя.
Это называется "сломать обратную совместимость". Да и потом частенько при применении статических фабрик конструктор вообще делают приватным, так что вполне себе можно сделать так и точно об этом не беспокоиться:
public static function USD($amount) {
$money = new static();
$money->amount = $amount;
$money->currency = static::CURRENCY_USD;
return $money;
}
Просто в нашем случае конструктор полюбому будет требоват только сумму и валюту, два параметра. Если внезапно добавится третий аргумент, просто либо делаем его не обязательным, либо же заносим его напрямую в приватное свойство.
Собственно в этом соль статических методов-фабрик. Мы можем объявлять для объекта разные "конструкторы" со своими ограничениями. Вроде у нас есть два способа создать объект, и для одного нужно два аргумента а для другого 4 и не меньше.
<?php
final class Money
{
private $amount;
public function getAmount()
{
return $this->amount;
}
public function add($amount)
{
return new self($this->amount + $amount, $this->currency);
}
}
Я что-то не понял? Или откуда тут взялся $this->currency?
Это валюта, в которой хранится сумма. Конструктора просто не хватает в примере. Что-то типа такого должно быть
final class Money
{
const CURRENCY_USD = 1;
private $amount;
private $currency;
private function __construct($amount, $currency)
{
$this->amount = $amount;
$this->currency = $currency;
}
public static function USD($amount) {
return new static($amount, self::CURRENCY_USD);
}
public function getAmount()
{
return $this->amount;
}
public function add($amount)
{
return new self($this->amount + $amount, $this->currency);
}
}
public function add($amount)
{
return new self($this->amount + $amount, $this->currency);
}
Если вызываешь add у объекта, то ждешь, что добавление будет именно к этому объекту. В чем проблема была через статик дублировать.
С другой стороны, то же самое различие у стандартных DateTime и DateTimeImmutable уже давно, так что удивлять особо не должно.
Ну заблуждени тут из ваших личных привычек. Лично меня подобное не смущает. Ну и опять же вопрос в том что имутабельность это хорошо (потому что можно всегда вывести типы и отследить стэйт не запуская код) но получать новые значения все еще нужно. И проще клонировать объект при изменениях (можно частично если эти части не меняются).
Ну и если вы все еще считаете что «это не очевидно» и т.д. предлагаю вам не личные субъективные ощущения (или мои) использовать, а провести полноценное исследование данного вопроса. Тогда можно будет делать выводы.
> Ну и если вы все еще считаете что «это не очевидно» и т.д. предлагаю вам не личные субъективные ощущения (или мои) использовать, а провести полноценное исследование данного вопроса.
Не конструктивно. На сколько я понимаю, вы не проводили исследование и точно не знаете, что у неизменяемого объекта лучше делать методы из названия которых предполгается, что объект будет изменен, но вдруг эти методы начинают возвращать клонированный новый объект якобы для подхода в стиле ФП.
> Ну и опять же вопрос в том что имутабельность это хорошо (потому что можно всегда вывести типы и отследить стэйт не запуская код) но получать новые значения все еще нужно. И проще клонировать объект при изменениях (можно частично если эти части не меняются).
Я не против клонирования неизмениямых объектов, я против клонирования этих объектов через методы этого объекта, предполгаюащие изменение самого объекта.
Можно ввести статический метод и клонировать через него. Только на входе у него будет source объект и значение, которое нужно получить в новом объекете.
final class Money
{
public static function add(Money $source, double $sum): Money
{
// ...
}
}
К тому же изменяемые объекты так же можно делать неизменяемыми, для этого можно создавать обертки:
class Mutable
{
protected $val;
public function __construct(int $val)
{
$this->val = $val;
}
public function getVal(): int
{
return $this->val;
}
public function add(int $val): void
{
$this->val += $val;
}
}
class Immutable extends Mutable
{
public static function addAndClone(Immutable $immutable, int $val): Immutable
{
return new Immutable($immutable->getVal() + $val);
}
public function add(int $val): void
{
throw new \RuntimeException('Immutable value.');
}
}
Неизменяемые объекты в PHP