Пункт 2 Розглянемо конструктора, коли стикаємося з багатьма параметрами конструктора Створення та знищення Java

Ця глава з книги

Ця глава з книги

Цей розділ з книги 

Пункт 2: Розглянемо конструктора, коли стикаємося з багатьма параметрами конструктора

Статичні заводи та конструктори поділяють обмеження: вони погано масштабуються до великої кількості необов’язкових параметрів. Розглянемо випадок із класом, який представляє ярлик “Факти харчування”, який з’являється на упакованих продуктах. Ці етикетки містять декілька обов’язкових полів - розмір порції, порції в упаковці та калорії на порцію - і понад двадцять необов’язкових полів - загальний жир, насичені жири, трансжир, холестерин, натрій тощо. Більшість продуктів мають ненульові значення лише для кількох із цих необов’язкових полів.

коли

Який тип конструкторів чи статичних фабрик ви повинні написати для такого класу? Традиційно програмісти застосовують шаблон телескопічного конструктора, в якому ви надаєте конструктор лише необхідних параметрів, інший - з одним необов’язковим параметром, третій - з двома необов’язковими параметрами тощо, завершуючись конструктором із усіма необов’язковими параметрами. Ось як це виглядає на практиці. Для стислості показано лише чотири необов’язкові поля:

Коли ви хочете створити екземпляр, ви використовуєте конструктор із найкоротшим списком параметрів, що містить усі параметри, які ви хочете встановити:

Зазвичай для цього виклику конструктора потрібно багато параметрів, які ви не хочете встановлювати, але ви все одно змушені передавати значення для них. У цьому випадку ми передали значення 0 для жиру. З «лише» шістьма параметрами це може здатися не так погано, але швидко виходить з-під контролю, оскільки кількість параметрів збільшується.

Коротко, шаблон телескопічного конструктора працює, але важко написати код клієнта, коли є багато параметрів, і важче все-таки його прочитати. Читач залишається здивованим, що означають усі ці значення, і повинен ретельно підрахувати параметри, щоб з’ясувати це. Довгі послідовності однаково набраних параметрів можуть спричинити незначні помилки. Якщо клієнт випадково скасує два таких параметри, компілятор не скаржиться, але програма буде поводитися неправильно під час виконання (Елемент 40).

Другою альтернативою, коли ви стикаєтеся з багатьма параметрами конструктора, є шаблон JavaBeans, в якому ви викликаєте безпараметричний конструктор для створення об'єкта, а потім викликаєте методи встановлення для встановлення кожного необхідного параметра та кожного необов'язкового параметра, що цікавить:

Ця схема не має жодних недоліків конструкції телескопічного конструктора. Створити екземпляри легко, хоча і трохи багатослівно, і легко прочитати отриманий код:

На жаль, шаблон JavaBeans має свої серйозні недоліки. Оскільки конструкція розділена на кілька дзвінків, JavaBean може перебувати в суперечливому стані ще на етапі його побудови. Клас не має можливості забезпечити узгодженість лише шляхом перевірки правильності параметрів конструктора. Спроба використовувати об’єкт, коли він перебуває у несумісному стані, може спричинити помилки, віддалені від коду, що містить помилку, і тому важко налагодити. Пов’язаний недолік полягає в тому шаблон JavaBeans виключає можливість зробити клас незмінним (Пункт 15), і вимагає додаткових зусиль з боку програміста для забезпечення безпеки потоків.

Можна зменшити ці недоліки шляхом ручного «заморожування» об’єкта, коли його конструкція завершена і не дозволяючи використовувати його до морозу, але цей варіант є громіздким і рідко використовується на практиці. Більше того, це може спричинити помилки під час виконання, оскільки компілятор не може переконатися, що програміст викликає метод freeze на об'єкті перед його використанням.

На щастя, є третя альтернатива, яка поєднує безпеку шаблону телескопічного конструктора та читабельність шаблону JavaBeans. Це форма шаблону Builder [Gamma95, с. 97]. Замість того, щоб робити бажаний об'єкт безпосередньо, клієнт викликає конструктор (або статичну фабрику) з усіма необхідними параметрами і отримує об'єкт будівельника. Потім клієнт викликає сетероподібні методи об’єкта конструктора для встановлення кожного необов’язкового параметра, що цікавить. Нарешті, клієнт викликає безпараметричний метод побудови для генерації об’єкта, який є незмінним. Конструктор - це статичний клас-член (Елемент 22) класу, який він будує. Ось як це виглядає на практиці: