Давайте посмотрим на варианты, где мы можем разместить код проверки:
- Внутри сеттеры у застройщика.
- Внутри
build()
метода.
- Внутри
build()
созданного объекта: он будет вызываться в методе при создании объекта.
Вариант 1 позволяет нам обнаруживать проблемы раньше, но могут быть сложные случаи, когда мы можем проверять ввод только с полным контекстом, таким образом, делая по крайней мере часть проверки в build()
методе. Таким образом, выбор варианта 1 приведет к несогласованности кода, при котором часть проверки выполняется в одном месте, а другая часть - в другом.
Вариант 2 не намного хуже, чем вариант 1, потому что, как правило, сеттеры в компоновщике вызываются непосредственно перед build()
, особенно в свободно используемых интерфейсах. Таким образом, в большинстве случаев все еще возможно обнаружить проблему достаточно рано. Однако, если построитель - не единственный способ создания объекта, это приведет к дублированию проверочного кода, поскольку он должен быть везде, где вы создаете объект. Наиболее логичным решением в этом случае будет поставить проверку как можно ближе к созданному объекту, то есть внутри него. И это вариант 3 .
С твердой точки зрения, размещение проверки в компоновщике также нарушает SRP: класс компоновщика уже несет ответственность за агрегирование данных для построения объекта. Валидация - это заключение договоров по собственному внутреннему состоянию, это новая обязанность проверять состояние другого объекта.
Таким образом, с моей точки зрения, не только лучше потерпеть неудачу поздно с точки зрения проектирования, но также лучше потерпеть неудачу внутри созданного объекта, а не в самом сборщике.
UPD: этот комментарий напомнил мне еще одну возможность, когда проверка внутри компоновщика (вариант 1 или 2) имеет смысл. Это имеет смысл, если у застройщика есть свои собственные контракты на объекты, которые он создает. Например, предположим, что у нас есть конструктор, который создает строку с определенным содержимым, скажем, список диапазонов номеров 1-2,3-4,5-6
. Этот строитель может иметь метод, как addRange(int min, int max)
. Результирующая строка ничего не знает об этих числах, и не должна знать. Сам строитель определяет формат строки и ограничения на числа. Таким образом, метод addRange(int,int)
должен проверять введенные числа и генерировать исключение, если max меньше min.
Тем не менее, общее правило будет заключаться в проверке только контрактов, определенных самим застройщиком.