Як уникнути шаленої кількості інтерфейсів в інтерфейсі користувача з введенням залежності?


8

Проблема
Я нещодавно багато читав про те, що Singletons є поганим, і як ін'єкція залежності (яку я розумію як "використання інтерфейсів") краще. Коли я реалізував частину цього за допомогою зворотних викликів / інтерфейсів / DI та дотримуючись принципу сегрегації інтерфейсу, я закінчився безладом.

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

Весь шлях на вершині ієрархії користувальницького інтерфейсу був класом Application, що містив інформацію про поточний вибір та посилання на 3d-модель, яка повинна відображати зміни. Клас додатків впроваджував 8 інтерфейсів, і це була лише кругла п'ята частина продуктів (/ інтерфейсів).

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

Питання:
Один сингтон може підходити до цього проекту?
Якщо ні, чи є фундаментальний недолік у моєму мисленні та / або здійсненні DI, який робить його таким громіздким?

Додаткова інформація про проект
Тип: Кошик кошик для квартир, з прибамбасами
Розмір: 2 людино-місяців для коду і призначеного для користувача інтерфейсу
Підтримка: Немає запуску оновлення, але , можливо , «версія 2.0» пізніше
середовище: Використання C # в Unity, який використовує Entity Компонентна система

Майже у всіх випадках взаємодія користувача запускає кілька дій. Наприклад, коли користувач вибирає предмет

  • частину інтерфейсу, що показує цей елемент, та його опис потрібно оновити. Для цього також потрібно отримати деяку інформацію від 3d-моделі, щоб розрахувати ціну.
  • далі вгору користувальницький інтерфейс, загальну загальну ціну потрібно оновити
  • відповідну функцію в класі на 3d-моделі потрібно викликати для відображення змін

DI - це не лише використання інтерфейсів, це можливість замінювати конкременти, що особливо корисно у сфері тестування одиниць ...
Роббі Ді

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

@RobbieDee Так, DI - це приблизно більше, але я не можу бачити ситуації, коли використання інтерфейсу не DI. І якщо сингтон не є кращим рішенням - яке я також припускаю, - чому тоді кращий варіант настільки безладний? Це моє головне питання, але я хотів тримати його відкритим, оскільки іноді загальне правило не застосовується.
Р. Шмітц

Влаштування інтерфейсу-бетонування також є особливістю глузування рам. Вони також були в мовах ОО протягом декількох десятиліть ...
Роббі Ді

Я не розумію вашої точки зору.
Р. Шмітц

Відповіді:


4

Я думаю, що питання є симптомом, а не рішенням.

Нещодавно я багато читав про те, що Singletons є поганим, і про те, як краще вводити залежність (яку я розумію як "використання інтерфейсів"). Коли я реалізував частину цього за допомогою зворотних викликів / інтерфейсів / DI та дотримуючись принципу сегрегації інтерфейсу, я закінчився безладом.

Рішення, яке шукає проблему; що і нерозуміння цього, мабуть, псує ваш дизайн. Ви читали це ТАКЕ питання щодо DI проти Singleton, різних понять чи ні? Я читав, що як просто загортати одиночку, так що клієнту не доведеться мати справу з синглетом. It.is.just.good.old.encapsulation. Я думаю, що це місце.


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

Спочатку побудуйте менші шматочки, а потім передайте їх у конструктор речі, до якої вони належать, і передайте цю більшу річ у конструктор наступної більшої речі ...

Якщо у вас складні проблеми з будівництвом, використовуйте заводський або будівельний зразок. Підсумок полягає в тому, що складна конструкція втягується у власний клас, щоб підтримувати інші класи акуратними, чистими, зрозумілими тощо.


Клас додатків впроваджував 8 інтерфейсів, і це була лише кругла п'ята частина продуктів (/ інтерфейсів).

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

Цікаво, чи ваш дизайн "важкий". Здається, що ми намагаємось зробити один клас таким, щоб це було все, або все, що воно могло бути. І той факт, що це клас UI, а не клас бізнес-домену, насправді змушує замислитися над розділенням проблем.

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


... 3d модель, яка повинна відображати зміни.

Значна частина цього може вписатись у спеціальні класи колекцій. Це також може бути незалежною класовою структурою для себе через глибину та складність. Ці дві речі не є взаємовиключними.

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


Дизайн та DI

90% усіх ін'єкцій залежності, які ви коли-небудь робите, - це проходження параметрів конструктора. Так каже quy, який написав книгу . Добре спроектуйте свої класи та уникайте забруднення цього роздуму з деяким розпливчастим уявленням про необхідність використання контейнерів із вмістом DI. Якщо вам це потрібно, ваш дизайн запропонує вам так би мовити.


Сфокусуйтесь на моделюванні торгового домену для квартир.

Уникайте підходу Джессіки Сімпсон до дизайну : "Я абсолютно не знаю, що це означає, але я хочу цього".

Далі просто неправильно:

  • Я повинен використовувати інтерфейси
  • Я не повинен використовувати синглтон
  • Мені потрібен DI (що б це не було)
  • Я повинен використовувати склад, а не спадщину
  • Я повинен уникати спадкування
  • Мені потрібно використовувати візерунки

Я намагався позбутися від усіх використовуваних синглів, а деякі речі, про які ви сказали, траплялися більш-менш автоматично. У решті теж багато сенсу, і я буду приймати ваші поради та читати про шаблон відвідувачів тощо. Загалом, добре написана відповідь, дякую!
Р. Шмітц

Тільки один момент, і я не намагаюся бути допомогою вампіра тут, але це свого роду частина початкового питання: загальний консенсус (і воно засноване на поважні причини) , здається, що ви дійсно не повинні використовувати одинарний. Ви пишете "" Я не повинен використовувати синглтон "- це неправильно" - в якій ситуації було б доречним використовувати його тоді?
Р. Шмітц

Все, що я говорю, - це "залежить". Занадто часто я бачу сентенції, взяті досить буквально.
radarbob

3

"Класова герархія" - це трохи червоний прапор. Гіпотетична: веб-сторінка з 5 віджетами. Сторінка не є предком жодного з віджетів. Він може містити посилання на ці віджети. Але це не предок. Замість класової спадкоємності подумайте про використання композиції. Кожен з 5-ти віджетів може бути сконструйований самостійно, без посилання на інші віджети чи верхню сторінку. Потім головна сторінка складається з достатньою інформацією для створення базової сторінки та компонування об’єктів віджетів (колекції), які передаються їй. Сторінка відповідає за макет тощо, але не за побудову та логіку віджетів.

Після використання композиції, DI - ваш найкращий друг. DI дозволяє змінювати кожен віджет на будь-яку версію або тип віджета, визначений у DI. Побудова віджетів відображається в DI та відокремлена від верхньої сторінки. Можливо, навіть склад колекції можна визначити у вашому DI. На верхній сторінці виконується макет на основі віджетів, переданих до нього, як слід. Не потрібно змінювати конструктор верхньої сторінки. На верхній сторінці потрібна лише логіка для компонування віджетів та передачі інформації в / з віджету на основі визначених інтерфейсів.

Замість того, щоб передавати слухачам вгору та вниз по ланцюжку композиції, додайте колекції слухачів ті віджети, які їй потрібні. Введіть колекцію у видавець, щоб вони могли публікувати колекцію. Вставте колекцію слухачам, щоб вони могли додати себе до колекції. Колекція розрізає всі об'єкти в ланцюжку композиції.


Вибачте, "ієрархія класів" була неправильною формулюванням тут; це насправді не ієрархія класів, а скоріше ієрархія інтерфейсу користувача. "Віджети" не є підкласами класу додатків, але "сторінка" містить посилання на них, щоб публікувати оновлення інтерфейсу користувача. Це було дуже перевірено з цією структурою, але також було багато накладних витрат, особливо у конструкторів, просто передаючи багато слухачів для своїх (інтерфейсу) дітей.
Р. Шмітц

@ R.Schmitz: Чи мала значення накладні витрати? Чи був інтерфейс інтерфейсу млявим, і в чому винна конструкція, яку ви описали?
Роберт Харві

@ R.Schmitz Чи можете ви детальніше розглянути питання про "передачу багатьох слухачам"? Можливо, мій досвід роботи з DI в C # низький, але щось підказує мені, що не було б необхідності (принаймні в конструкторі) при належному дизайні.
Katana314

@RobertHarvey Зовсім не втрачає продуктивність, йдеться лише про читабельність.
Р. Шмітц

@ Katana314 Наприклад, коли додається елемент, 3dмодель потребує оновлення, і вона не належить до жодної з категорій продуктів, тому вона посилається на клас додатків, який слухає додавання / вилучення / зміну елементів. Зрештою, це було б майже однаково для кожної категорії товарів. Інші частини інтерфейсу також реагують (і слухають), але повідомлення повинно подорожувати до вершини, оскільки саме там знаходиться посилання 3dмоделі та фактичні дані (які потім також оновлюються).
Р. Шмітц
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.