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


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.