Есть строка-значение, есть число-значение, есть структура-значение, есть объект-значение. Названо объектом и советуется использовать потому, что у объекта есть не только состояние, но и поведение. То есть туда, в отличие от примитива или структуры, можно впрограммировать свою логику. Даже если в языке String – объект, то там всё равно есть только стандартные методы, а не наши собственные. Чтобы добавить своё поведение нужно либо обернуть примитив в свой объект, либо отнаследоваться.
Например, тобы не возиться отдельно с float x и float y можно придумать свой тип Point(float x, float y) и добавить туда свой метод move(dx, dy). И потом добавить Vector(Point start, Point end) с add(Vector other). И Poligon(points) с методами добавления точек.
Так что Value Object – это просто продвинутый пользовательский тип в виде объекта с пользовательским поведением. И эти значения мы создаём в любом количестве, сравниваем, передаём в функции и возвращаем оттуда также, как работаем с оригинальными int, float и stri