И когда придётся внести какие-то изменения, даже не очень значительные, вдруг окажется, что просто объявить новый класс, который замкнёт функцию от двух точек функцией одной точки, не выходит... И начнутся танцы с бубном.А для бизнес-логики - ровно что надо.
Я, сознаюсь, с этой книгой не знаком. Но абсолютно уверен, что Эванс ничего подобного определению преобразований, стрелочных объектов, в виде методов классов-значений не писал.Эванса почитай, поймешь о чем речь.
После нескольких страниц все-таки выяснилось, что за красивыми словами скрывается обычная некомпетентность. Сам по себе факт того, что ты считаешь анемичность признаком ООП — это не так страшно, это ошибка многих новичков и не только, но все-таки я ожидал от дискуссии большего.Есть два варианта.
ValueObject предоставляет данные -- тогда это просто запись, значение, у него нет никаких направлений редукции.
ValueObject представляет абстрактный процесс получения данных, активные данные. Тогда сам ValueObject не более, чем интерфейс, у него нет ни конструктора, ни полей.
ValueObjects -- это записи, полностью определяемые своими составляющими. Когда Эванс говорит о related functionality, речь идёт о функциональности записи. Он работает с языком Java, который не предоставляет ничего подобного записи, такую абстракцию нужно создавать самому, причём в Java есть определённые конвенции, как именно это должно выглядеть.When you care only about the attributes of an element of the model, classify it as a VALUE OBJECT.
Making it express the meaning of attributes it conveys and give it related functionality. Treat the
VALUE OBJECT as immutable. Don’t give it any identity and avoid the design complexities necessary
to maintain ENTITIES.
Цитаты великих людей.А вот Entities -- это ValueObject
Анемичность, о которой пишет Фаулер, это вовсе не то, что каждая точка должна содержать в себе все возможные вычислимые от точки функции. Просто напихать методов в environment-- это ещё далеко не объектно-ориентированное программирование.не любят анемичность
// from miles to km
$meterConversion = 1.609344;
$geopointDistance = $dist * $meterConversion;
Ты можешь это рассматривать, как частный случай операции типа ComplexNumber::add(), ComplexNumber::multiply(), etc. В нашем контексте эта операция будет выглядеть именно так, именно вот такой вот точностью, которая согласована с бизнесом.И мне тоже кажется странным что Point сам считает расстояние до другого поинта.
Модель пишется для какой-то конкретной предметной области, а не для абстрактной. Мы делаем модель для точки на планете Земля и это абсолютно нормально, что мы хардкодим радиус Земли.Да еще и сам внутри магичестким числом диаметр земли определяет.
Да, для меня это норм.@Вурдалак
А это тебе тоже норм? В той же функции... что и диаметр Земли и расчет расстояния...PHP:// from miles to km $meterConversion = 1.609344; $geopointDistance = $dist * $meterConversion;
Это, наверное, по той причине, что ты хочешь иметь универсальный класс Point, то время как модель должна быть конкретной для решения конкретных бизнес-проблем.Для меня это был бы идеальный Value object, если убрать две функции:
getApproximateRoadDistance
getCartographicDistance
Нет. http://c2.com/cgi/wiki?DataEnvyЧто мешает сделать DistanceCalculator класс? Лень?
Для ComplexNumber::add() ты бы делал ComplexNumberAdder?Что мешает сделать DistanceCalculator класс? Лень?
Почему абстрактными-то?Но повторю, расчет расстояния между двумя абстрактными точками, в котором вдруг появляется радиус планеты и коэфициент между милями и км, это совсем не то, что комплексные числа, в которых операция add строго замкнута вокруг ComplexNumber.
Мы пишем ее для контекста TripPlanner фирмы Acme.
Он мог бы быть, но в самой модели нам бы пришлось бы передать вполне конкретные значения, т.е.Этот DistanceCalculator мог бы из довольно абстрактного Point, считать расстояния для конкретной планеты и в конкретных километрах.. или милях.
namespace Acme/TripPlanner/TripDomain;
final class Point
{
// ...
public function getCartographicDistance(Point $point)
{
// DistanceCalculator is some generic library
return DistanceCalculator::calcDistanceBeetweenTwoPointsWithSphericalCoordinates(
$this->lat, $this->lng,
$point->lat, $point->lng,
DistanceCalculator::EARTH_RADIUS,
DistanceCalculator::KILOMETERS
);
}
}