Давайте розглянемо варіанти, де ми можемо розмістити код перевірки:
- Всередині сетерів у будівельнику.
- Всередині
build()
методу.
- Всередині сконструйованої сутності: вона буде викликана
build()
методом під час створення об'єкта.
Варіант 1 дозволяє виявляти проблеми раніше, але можуть бути складні випадки, коли ми можемо перевірити вхід лише з повним контекстом, таким чином, зробивши принаймні частину перевірки build()
методу. Таким чином, вибір варіанту 1 призведе до непослідовного коду, частина перевірки виконується в одному місці, а інша - в іншому місці.
Варіант 2 не є значно гіршим, ніж варіант 1, тому що, як правило, сеттери в програмі запускаються безпосередньо перед build()
, особливо, у вільних інтерфейсах. Таким чином, в більшості випадків проблему все-таки можливо виявити досить рано. Однак якщо конструктор - це не єдиний спосіб створити об’єкт, це призведе до дублювання коду перевірки, тому що вам потрібно мати його скрізь, де ви створюєте об'єкт. Найбільш логічним рішенням у цьому випадку буде поставити перевірку якомога ближче до створеного об’єкта, тобто всередині нього. І це варіант 3 .
З точки зору SOLID, введення валідації в builder також порушує SRP: клас будівельника вже несе відповідальність за агрегацію даних для побудови об'єкта. Валідація - це встановлення договорів про власний внутрішній стан, це нова відповідальність перевірити стан іншого об’єкта.
Таким чином, з моєї точки зору, не тільки краще пізно провалитись з точки зору проектування, але і краще провалитися всередині побудованої сутності, а не в самому будівельнику.
UPD: цей коментар нагадав мені ще одну можливість, коли валідація всередині будівельника (варіант 1 або 2) має сенс. Це має сенс, якщо у будівельника є власні договори на об’єкти, які він створює. Наприклад, припустимо, що у нас є конструктор, який будує рядок із певним вмістом, скажімо, списком діапазонів чисел 1-2,3-4,5-6
. Цей будівельник може мати такий метод addRange(int min, int max)
. Отриманий рядок нічого не знає про ці числа, а також не повинен знати. Сам конструктор визначає формат рядка та обмеження чисел. Таким чином, метод addRange(int,int)
повинен підтвердити вхідні числа та винести виняток, якщо max менше, ніж min.
Однак, загальним правилом буде затвердження лише тих договорів, визначених самим будівельником.