Структурные и Именованные типы. Поведение или Представление?

fixxxer

К.О.
Партнер клуба
Мы с разных позиций смотрим. С точки зрения некоторой библиотеки общего назначения это было бы ужасно. А для бизнес-логики - ровно что надо.

Эванса почитай, поймешь о чем речь.
 

Lionishy

Новичок
А для бизнес-логики - ровно что надо.
И когда придётся внести какие-то изменения, даже не очень значительные, вдруг окажется, что просто объявить новый класс, который замкнёт функцию от двух точек функцией одной точки, не выходит... И начнутся танцы с бубном.
Зачем нужна замкнутость?

Бизнес-логика -- это просто композиция абстракций (правильное соединение абстракций), определённых для предметной области. Любая предметная программа состоит из двух слоёв: библиотека предметной области и программа, решающая конкретную задачу предметной области. Программа -- это верно соединённые между собой объекты. Всё остальное -- это библиотека общего для предметной области назначения.

Эванса почитай, поймешь о чем речь.
Я, сознаюсь, с этой книгой не знаком. Но абсолютно уверен, что Эванс ничего подобного определению преобразований, стрелочных объектов, в виде методов классов-значений не писал.
Либо у Вас, возможно, возникли сложности с чтением и недопонимание с автором, потому что у самого автора, возможно, есть неразрешённые проблемы в концепции, как у Бертрана Мейера с нуль-методами command, например.
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
Есть два варианта.
ValueObject предоставляет данные -- тогда это просто запись, значение, у него нет никаких направлений редукции.
ValueObject представляет абстрактный процесс получения данных, активные данные. Тогда сам ValueObject не более, чем интерфейс, у него нет ни конструктора, ни полей.
После нескольких страниц все-таки выяснилось, что за красивыми словами скрывается обычная некомпетентность. Сам по себе факт того, что ты считаешь анемичность признаком ООП — это не так страшно, это ошибка многих новичков и не только, но все-таки я ожидал от дискуссии большего.
 

Lionishy

Новичок
@fixxxer,
Здесь, собственно всё сразу ясно.
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.
ValueObjects -- это записи, полностью определяемые своими составляющими. Когда Эванс говорит о related functionality, речь идёт о функциональности записи. Он работает с языком Java, который не предоставляет ничего подобного записи, такую абстракцию нужно создавать самому, причём в Java есть определённые конвенции, как именно это должно выглядеть.

А вот Entities -- это ValueObject, которые являются абстракциями процессов редукции к своим данным, активные данные.

Всё выстроено так, как и должно быть: у Вас есть данные и выражения, выражения Entities определяют операционную семантику (т.е. куда продвигаться), а ValueObject -- это выражения значения, которые определяют остановку операционной семантики, результаты вычислений.
 

Adelf

Administrator
Команда форума
Я конечн извиняюсь что вклиниваюсь в эту дискуссию, которая наконец зашла в тупик :)
Но я тоже не люблю когда обьекты данных содержат логику. Т.е. я обожаю анемичность. И мне тоже кажется странным что Point сам считает расстояние до другого поинта. Да еще и сам внутри магичестким числом диаметр земли определяет. Но тут я не догматик. Я знаю, что все эти Фаулеры и Эвансы не любят анемичность. И наверняка есть за что. Может приведете тут ссылок или аргументов... чтобы я понял в чем тут соль.
 

Lionishy

Новичок
не любят анемичность
Анемичность, о которой пишет Фаулер, это вовсе не то, что каждая точка должна содержать в себе все возможные вычислимые от точки функции. Просто напихать методов в environment-- это ещё далеко не объектно-ориентированное программирование.

Анемичность -- это разделение на данные и функции таким образом, что функции не могут быть данными. В частности примеры с Money и Point -- это совершенно незамкнутые системы, это они самые и есть "анемичные модели".

Здача ООП сделать вот так, но не только для ограниченной семантики: аппликация, абстракция, композиция, -- а для произвольной, когда можно выразить непосредственно операционную семантику, не прибегая к опосредованному выражению через комбинации трёх функциональных действий.

Именно гибкость объектного похода, как мне кажется, и обеспечила возможность внедрения замкнутых алгебр в языки типа C. То есть, объектный подход легче адаптируется, чем функциональный. Но в сущности, задачи у них одни.
 

Adelf

Administrator
Команда форума
@Вурдалак
PHP:
  // from miles to km
  $meterConversion = 1.609344;
  $geopointDistance = $dist * $meterConversion;
А это тебе тоже норм? В той же функции... что и диаметр Земли и расчет расстояния...

Для меня это был бы идеальный Value object, если убрать две функции:
getApproximateRoadDistance
getCartographicDistance
 

Вурдалак

Продвинутый новичок
И мне тоже кажется странным что Point сам считает расстояние до другого поинта.
Ты можешь это рассматривать, как частный случай операции типа ComplexNumber::add(), ComplexNumber::multiply(), etc. В нашем контексте эта операция будет выглядеть именно так, именно вот такой вот точностью, которая согласована с бизнесом.

Да еще и сам внутри магичестким числом диаметр земли определяет.
Модель пишется для какой-то конкретной предметной области, а не для абстрактной. Мы делаем модель для точки на планете Земля и это абсолютно нормально, что мы хардкодим радиус Земли.

Мы не пишем абстрактную точку в вакууме. Мы пишем ее для контекста TripPlanner фирмы Acme. И здесь у нас есть вполне конкретные понятия о том, что считать расстоянием (потому что расстояние можно еще считать, например, по дорожным путям, хотя сам точка будет представлена теми же координатами).

@Вурдалак
PHP:
  // from miles to km
  $meterConversion = 1.609344;
  $geopointDistance = $dist * $meterConversion;
А это тебе тоже норм? В той же функции... что и диаметр Земли и расчет расстояния...
Да, для меня это норм.

Представь на секунду, например, что DateTime был бы анемичным. Что, например, он бы допускал дату типа 30-е февраля. Ты скажешь, что это не имеет никакого смысла, но ты так говоришь, только потому что DateTime работает с Григорианским календарем, а не сферическим календарем в вакууме.
 

Вурдалак

Продвинутый новичок
Для меня это был бы идеальный Value object, если убрать две функции:
getApproximateRoadDistance
getCartographicDistance
Это, наверное, по той причине, что ты хочешь иметь универсальный класс Point, то время как модель должна быть конкретной для решения конкретных бизнес-проблем.
 

Adelf

Administrator
Команда форума
Что мешает сделать DistanceCalculator класс? Лень?
 

Adelf

Administrator
Команда форума
DateTime вполне можно было бы назвать GregorianDataTime. Просто народ не стал делать длинное название.
Point этот кстати неплохо бы назвать GeoPoint чтоли хотя бы :)
 

Adelf

Administrator
Команда форума
Во. Одна ссылка уже.
Но тут как раз немного другой случай. Этот DistanceCalculator мог бы из довольно абстрактного Point, считать расстояния для конкретной планеты и в конкретных километрах.. или милях. Не.. может это оверинжиниринг уже.. не знаю.
 

Adelf

Administrator
Команда форума
Нет. Реализовал бы operator + :)
Если уж сахар, так побольше.

Но повторю, расчет расстояния между двумя абстрактными точками, в котором вдруг появляется радиус планеты и коэфициент между милями и км, это совсем не то, что комплексные числа, в которых операция add строго замкнута вокруг ComplexNumber.
 

Вурдалак

Продвинутый новичок
Но повторю, расчет расстояния между двумя абстрактными точками, в котором вдруг появляется радиус планеты и коэфициент между милями и км, это совсем не то, что комплексные числа, в которых операция add строго замкнута вокруг ComplexNumber.
Почему абстрактными-то?
Мы пишем ее для контекста TripPlanner фирмы Acme.
 

Вурдалак

Продвинутый новичок
Этот DistanceCalculator мог бы из довольно абстрактного Point, считать расстояния для конкретной планеты и в конкретных километрах.. или милях.
Он мог бы быть, но в самой модели нам бы пришлось бы передать вполне конкретные значения, т.е.
PHP:
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
        );
    }
}
DistanceCalculator здесь мог бы быть какой-то сторонней библиотекой.
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Ну мне они показались абстрактными. Ибо такими они и оказываются если убрать эти две функции подсчета. Странно, что именно эти функции просто своим наличием меняют смысл основного класса. Ну я понял тебя... функция тестится нормально... в принципе ничего не мешает. Если километро-мили или радиус планеты станут какими-то значимыми понятиями в Domain, думаю просто последует рефакторинг. Возможно, я просто обзавелся привычками, которые постоянно ведут к оверинжинирингу... Частично ты сам в этом виноват, некоторые твои фразы тут :)
 

Adelf

Administrator
Команда форума
Не.. Мой DistanceCalculator уже был бы как раз частью нашей бизнес-логики. Со всеми радиусами и километрами. Если надо, он юзал бы абстрактный DistanceCalc подставляя туда нужное. Мне просто нравится чистый обьект Point. Я не хочу марать его бизнес-логикой.
 
Сверху