Уникаючи конструкторів з багатьма аргументами


10

Тож у мене є завод, який створює об’єкти різних класів. Усі можливі класи походять від абстрактного предка. Фабрика має файл конфігурації (синтаксис JSON) і вирішує, який клас створити, залежно від конфігурації користувача.

Щоб досягти цього, фабрика використовує boost :: property_tree для JSON-розбору. Він проходить птахом і вирішує, який конкретний об’єкт створити.

Однак у продуктів-об’єктів є багато полів (атрибутів). Залежно від класу конкретності, об’єкт має близько 5-10 атрибутів, в майбутньому може бути навіть більше.

Тож я не впевнений, як повинен виглядати конструктор об’єктів. Я можу придумати два рішення:

1) Конструктор продукту очікує, що кожен атрибут є параметром, таким чином, конструктор закінчить 10+ параметрів. Це буде некрасиво і призведе до довгих нечитабельних рядків коду. Однак перевага полягає в тому, що фабрика може проаналізувати JSON і викликати конструктор з правильними параметрами. Класу продукту не потрібно знати, що він створений завдяки конфігурації JSON. Не потрібно знати, що взагалі є JSON або конфігурація.

2) Конструктор продукту очікує лише одного аргументу, об'єкта property_tree. Тоді він може розібрати необхідну інформацію. Якщо інформація в конфігурації відсутня або знаходиться поза межами, кожен клас продукту може правильно реагувати. Фабриці не потрібно знати, які аргументи потрібні декільком продуктам. Фабриці також не потрібно знати, як реагувати у разі неправильної конфігурації. І інтерфейс конструктора уніфікований і малий. Але, як недолік, продукт повинен отримати необхідну інформацію з JSON, таким чином, він знає, як він побудований.

Я, як правило, віддаю перевагу рішенню 2). Однак я не впевнений, чи це хороший заводський зразок. Начебто неправильно повідомляти про продукт, що він створений з конфігурацією JSON. З іншого боку, нові продукти можна представити дуже просто.

Будь-які думки з цього приводу?



1
Я перейшов за вашим посиланням. Ось приклад у найкращій відповіді від щурячого виродка. Але яке питання вирішує цей "будівельник"? Там є кодова лінія DataClass data = builder.createResult () ;. Але метод createResults () все ще повинен отримати 10 параметрів в об’єкт DataClass. Але як? Здається, у вас є ще один шар абстракції, але конструктор DataClass не стає меншим.
— lugge86

Погляньте на конструктора та прототипу.
— Сільвіу Бурча

Сільвіу Бурча, я. Однак, використовуючи програму builder, як конструктор отримує параметри продукту? Десь там МАЄ бути жирним інтерфейсом. Конструктор - це ще один шар, але параметри повинні якось знайти свій клас у продуктовому класі.
— lugge86

1
Якщо ваш клас занадто великий, зміна аргументів конструктора не робить його не надто великим .
— Теластин

Відповіді:


10

Я б не робив варіант 2, оскільки тоді ви назавжди згорнули конструкцію вашого об'єкта за допомогою синтаксичного розбору дерева властивостей. Якщо вам комфортно з класом, який потребує такої кількості параметрів, ви повинні бути комфортними з конструктором, який потребує такої кількості параметрів, як життя!

Якщо ваша головна проблема полягає в читанні коду, ви можете використовувати модель конструктора, це, в основному, зупинка c ++ / java для відсутності названих аргументів. Ви закінчуєте речі, які виглядають приблизно так:

MyObject o = MyObject::Builder()
               .setParam1(val1)
               .setParam2(val2)
               .setParam3(val3)
             .build();

Тож тепер MyObject матиме приватний конструктор, який викликається в Builder :: build. Приємно, що це буде єдине місце, коли вам доведеться викликати конструктор з 10 параметрами. Фабрика дерев властивостей boost використовуватиме builder, і згодом, якщо ви хочете сконструювати MyObject безпосередньо або з іншого джерела, ви перейдете через конструктор. І в основному конструктор дозволяє чітко назвати кожен параметр під час передачі, щоб він був більш читабельним. Це, очевидно, додає деяку котельну плиту, тому вам доведеться вирішити, чи варто цього порівняти з тим, щоб просто викликати брудний конструктор або згуртувати деякі існуючі параметри в структури тощо. Просто кидаючи інший варіант на стіл.

https://en.wikipedia.org/wiki/Builder_pattern#C.2B.2B_Example


5

НЕ використовуйте другий підхід.

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

Або:

  • спробуйте згрупувати певні параметри, які, здається, представляють подібні речі в об’єкти
  • розділити поточний клас на кілька менших класів (маючи клас обслуговування з 10 параметрами, схоже, клас робить занадто багато речей)
  • залиште його таким, яким є, якщо ваш клас насправді не є послугою, а об'єктом значення

Якщо об'єкт, який ви створюєте, насправді не є класом, який відповідає за зберігання даних, вам слід спробувати перефактурувати код і розділити великий клас на менші.


Ну, логікою bsiness є фабрика, яка повертає продукцію, таким чином, бізнес-логіка не бачить матеріалів JSON / ptree. Але я бачу вашу думку, якщо Parser-код у конструкторі почувається неправильним.
— lugge86

Клас представляє віджет у графічному інтерфейсі для вбудованої системи, таким чином, 5+ атрибутів здається мені нормальним: x_coord, y_coord, backgroundcolor, frameize, framecolor, text ...
— lugge86

1
@ lugge86 Незважаючи на те, що ви використовуєте фабрику для розбору JSON і, таким чином, уникаєте виклику newабо побудови об'єктів у вашій бізнес-логіці, це не дуже хороший дизайн. Перевірте не шукайте розмов Мішко Гевери , який більш глибоко пояснює, чому заводський підхід, який ви натякали, поганий як з точки зору тестування, так і з точки зору читання. Крім того, ваш клас здається об'єктом даних, і для них, як правило, добре мати більше параметрів, ніж звичайний клас обслуговування. Мене б не надто турбувало.
— Енді

Я добре себе почуваю зі своїм фабричним підходом, але я перейду за вашим посиланням і подумаю про це. Однак фабрика не викликає сумнівів у цій темі. Ще питання, як налаштувати продукти ...
— lugge86

"наявність класу обслуговування з 10 параметрами здається, що клас робить занадто багато речей" Не в машинному навчанні. Будь-який алгоритм ML повинен мати тони настроюваних параметрів. Цікаво, що це правильний спосіб впоратися з цим при кодуванні ML.
— Сіюань Рен

0

Варіант 2 майже правильний.

Вдосконалений варіант 2

Створіть клас "лицьова сторона", завданням якого є взяти об'єкт структури JSON та вибрати біти та викликати заводські конструктори. Він бере те, що робить фабрика, і віддає його клієнту.

  • Фабрика абсолютно не має уявлення про те, що така штука JSON навіть існує.
  • Клієнт не повинен знати, які конкретні біти потребує завод.

По суті, "передній кінець" каже 2-х бобам: "Я маю справу з відредагованими замовниками, щоб інженерам не довелося! У мене є навички людей!" Бідний Том. Якби він сказав лише: "Я відв'язую клієнта від будівництва. Цей результат - це дуже згуртований завод"; він, можливо, втримав свою роботу.

Занадто багато аргументів?

Не для клієнта - передній зв'язок.

Передня частина - фабрика? Якщо не 10 параметрів, то найкраще, що ви можете зробити, - це зняти розпакування, якщо не оригінал JSON, то деякий DTO. Це краще, ніж передавати JSON на завод? Я ж кажу різницю.

Я б настійно розглядав можливість проходження окремих параметрів. Дотримуйтесь мети чистої, згуртованої фабрики. Уникайте занепокоєнь щодо відповіді @DavidPacker.

Пом'якшення "занадто багато аргументів"

  • Конструктори заводу або класу

    • беручи лише аргументи для конкретного побудови класу / об'єкта.
    • параметри за замовчуванням
    • необов'язкові параметри
    • названі аргументи
  • Групування аргументів на першому кінці

    • Вивчає, оцінює, підтверджує, встановлює і т.д. значення аргументів, керовані підписами конструктора вище.

"Фабрика абсолютно не має уявлення, що така штука JSON навіть існує" - ну, для чого тоді завод ?? Він приховує деталі створення продукту як від продукту, так і від споживача. Чому ще один клас повинен допомагати? Я добре з фабрично кажучи JSON. Можна реалізувати ще одну фабрику для розбору XML та впровадити "Абстрактний завод" у майбутньому ...
— lugge86

Містер Фабрик: "Який об'єкт ви хочете? ... Що це? Просто скажіть, який клас-об'єкт будувати". Файл конфігурації JSON є джерелом даних, як дядько Боб каже, "це деталь реалізації". Це може бути з іншого джерела та / або в іншій формі. Як правило, ми хочемо від'єднатись від конкретних деталей джерела даних. Якщо джерело чи форма зміниться, фабрика не буде. Враховуючи джерело + аналізатор, а фабрика як роз'єднані модулі робить обидва багаторазові.
— radarbob
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.