Введення залежності: чи слід використовувати рамку?


24

Нещодавно я працював над проектом Python, де ми зробили велику кількість ін'єкцій залежностей (тому що ми повинні робити тест на додаток), але не використовували жодної основи. Часом було трохи стомливо підключати всі залежності вручну, але в цілому це працювало чудово.

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

У тестах ми зробили те саме: якщо нам потрібно було кілька разів створити "тестову версію" об'єкта (тобто реального екземпляра, підкріпленого макетними об'єктами), у нас була функція створити цю "тестову версію" класу, який буде використовуватися в тестах.

Як я вже говорив, загалом це працювало чудово.

Зараз я вступаю в новий проект Java, і ми вирішуємо, чи використовувати рамку DI, чи робити DI вручну (як у попередньому проекті).

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

Редагувати: Я також хотів би додати питання: чи ви були свідком будь-якого проекту "професійного рівня", який робить DI вручну, без рамки?


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

4
Я думаю, ви вже перевірили, на випадок, якщо ви цього не зробите. Навіщо нам потрібні рамки для DI?
Лаїв

Відповіді:


19

Ключ DI контейнерів - абстракція . DI контейнери абстрагують цю дизайнерську проблему для вас. Як ви здогадуєтесь, він помітно впливає на код, часто перекладається на меншу кількість конструкторів, сеттерів, заводів та будівельників. Як наслідок, вони роблять ваш код більш вільно сполученим (завдяки базовому ІОК ), більш чистим та простим. Хоча не без витрат.

Фони

Роки тому подібне абстрагування вимагало від нас писати різні конфігураційні файли ( декларативне програмування ). Було фантастично бачити, як кількість LOC значно зменшується, але, хоча LOCSs зменшувалася, кількість конфігураційних файлів трохи збільшувалася. Для середніх або малих проектів це взагалі не було проблемою, але для більш великих проектів, щоб "збірка коду" розсіялася на 50% між дескрипторами коду та XML, стала проблемою ... Тим не менш, головна проблема полягала в тому, що сама парадигма. Це було досить негнучким, оскільки дескриптори залишали мало місця для налаштування.

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

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

З нижньої сторони ...

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

Це гандикап для тих, хто навчився DI з контейнерами DI. Вони не повністю розуміють актуальність моделей дизайну, належну практику та принципи, які були вилучені з контейнера. Я запитав розробників, чи знайомі вони з DI та його перевагами, і вони відповіли: - Так, я використовував Spring IoC -. (Що за чорт це означає?!?)

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

З позитивного боку ...

Продуктивність одного слова . Структури дозволяють зосередитись на тому, що дійсно має значення. Бізнес програми.

Незважаючи на коментовані недоліки, для багатьох із нас (робота яких обумовлена ​​строками та витратами) ці інструменти є неоціненним ресурсом. На мою думку, це має бути нашим головним аргументом на користь впровадження контейнерів DI. Продуктивність .

Тестування

Незалежно від того, чи будемо ми реалізувати чисті DI чи контейнери, тестування не буде проблемою. Зовсім навпаки. Ті ж контейнери часто дають нам макети для тестування одиниць поза коробкою. Протягом багатьох років я використовував свої тести як термометри. Вони мені кажуть, чи покладався я сильно на контейнерні споруди. Я говорю це тому, що ці контейнери можуть ініціалізувати приватні атрибути без сетерів чи конструкторів. Вони можуть вводити компоненти практично в будь-яке місце!

Звучить спокусливо правильно? Будь обережний! Не потрапляйте в пастку !!

Пропозиції

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

Щодо цієї практики:

Коли використовувати контейнери DI

Моя відповідь буде упереджена власним досвідом, який в основному на користь DI контейнерів (як я коментував, я сильно зосереджений на продуктивності, тому в мене ніколи не було потреби в чистому DI. Зовсім навпаки).

Думаю, ви знайдете цікаву статтю Марка Семана про цю тему, яка також відповідає на питання про те, як реалізувати чистий DI .

Нарешті, якби ми говорили про Яву, я б спробував спочатку поглянути на JSR330 - залежне введення .

Підбиття підсумків

Переваги :

  • Зниження витрат та економія часу. Продуктивність.
  • Менша кількість компонентів.
  • Код стає простішим і чистішим.

Недоліки :

  • DI делеговано третім сторонам. Ми повинні усвідомлювати їхні компроміси, сильні та слабкі сторони.
  • Крива навчання.
  • Вони швидко змушують вас забути деякі хороші звички.
  • Збільшення залежностей від проекту (більше лімб)
  • Контейнери на основі рефлексії потребують більше ресурсів (пам'яті). Це важливо, якщо ми обмежені ресурсами.

Відмінності з чистим DI :

  • Менше коду та більше файлів конфігурації чи приміток.

1
"Ці рамки не є приватними для вас, щоб робити тест одиниці чи перевірку цілісності, тому не переживайте про тестування." Що це означає? Формулювання змушує мене думати, що це помилка друку, але у мене виникають проблеми з її розшифровкою.
candied_orange

Це означає, що важка налагодження або використання фреймворків для тестування - недостатньо недоліків, щоб відмовитися від використання цих фреймворків. Тому що навіть якщо ви не любите їх, вони все ще мають переваги, які дійсно варто спробувати. Великі недоліки - це не самі рамки. Як ти їх використовуєш. Деякі добрі практики, такі як інтерфейси та сеттери, все ще потрібні, навіть якщо ваша рамка цього не робить. Нарешті, є хороші тести для тестування, які легко інтегруються з подібними рамками (DI)
Laiv

Якщо це, що ви маєте на увазі, врахуйте: "Ці рамки не заважають вам виконувати одиничні тести або тести на цілісність, тому не турбуйтеся про те, як вони впливають на тестування"
candied_orange

Сррі. Я намагаюся сказати, що він зможе перевірити свій код навіть із цими рамками. Незважаючи на абстракцію, тестування все ще можливо. Не соромтесь редагувати мою відповідь. Як ви бачите, моя англійська мова все ще далеко не гідна :-)
Laiv

1
Зауважте, що Dagger2 робить DI дещо іншим. Код клею генерується під час компіляції як звичайні, читаемі джерела Java, тому набагато простіше слідкувати за тим, як склеюються речі, а не мати справу з магією виконання.
Thorbjørn Ravn Andersen

10

На мій досвід, рамки введення залежності залежать від ряду питань. Деякі питання залежатимуть від рамки та інструментарію. Можуть існувати практики, що пом'якшують проблеми. Але це питання, які я вразив.

Неглобальні об’єкти

У деяких випадках потрібно вставити глобальний об’єкт: об’єкт, у якого запущена програма буде мати лише один екземпляр. Це може бути адреса MarkdownToHtmlRendererer, a DatabaseConnectionPool, адреса вашого сервера api і т. Д. У цих випадках рамки введення залежності працюють дуже просто, ви просто додаєте потрібну залежність до свого конструктора, і ви це отримали.

А як щодо об'єктів, які не є глобальними? Що робити, якщо вам потрібен користувач для поточного запиту? Що робити, якщо вам потрібна поточна активна транзакция бази даних? Що робити, якщо вам потрібен елемент HTML, відповідний ділу, який містить форму, в якій є текстове поле, яке щойно запустило подію?

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

Бібліотеки

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

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

Прихована складність

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

Підтримка IDE

Ваш IDE, ймовірно, не розуміє рамки введення залежності. На заводах, що працюють вручну, ви можете знайти всіх абонентів конструктора, щоб визначити всі місця, з яких об’єкт може бути побудований. Але виклики, створені рамкою DI, не знайдуть.

Висновок

Що ми отримуємо із системи введення залежності? Ми намагаємось уникати певних просторічних котельних плит, необхідних для інстанції об'єктів. Я все для усунення простодушних котельних плит. Однак підтримувати просту котельну плиту досить просто. Якщо ми збираємося замінити цю котельну плиту, нам слід наполягати на заміні її чимось простішим. Через різні питання, про які я говорив вище, я не думаю, що рамки (принаймні, як вони стоять) відповідають законопроекту.


Це дуже гарна відповідь, але я не уявляю, як використовувати контейнер IoC для бібліотеки класів. Мені це здається поганим дизайном. Я б очікував, що бібліотека мені явно надасть її залежно від того, чого вона вимагає.
RubberDuck

@RubberDuck, в моєму випадку я працював у великій компанії з великою кількістю проектів java, всі стандартизовані на одній і тій же схемі введення залежності. У цей момент для деяких команд стає заманливо експортувати бібліотеку, яка розраховує скласти рамку DI, а не надавати розумний зовнішній інтерфейс.
Вінстон Еверт

Це прикро @WinstonEwert. Дякуємо, що заповнили контекст для мене.
RubberDuck

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

IntelliJ розуміє CDI (Java EE стандарт DI)
Thorbjørn Ravn Andersen

3

Чи потрібна ін'єкція Java + залежності = рамки?

Ні.

Що мені купує рамка DI?

Побудова об'єкта відбувається мовою, що не є Java.


Якщо фабричні методи досить хороші для ваших потреб, ви можете зробити DI в java повністю каркас безкоштовно в 100% справжній pojo java. Якщо ваші потреби виходять за рамки, у вас є інші варіанти.

Шаблони дизайну «Банда з чотирьох» досягають багатьох чудових речей, але завжди мали слабкі місця, коли справа стосувалася креативних моделей. Сама Java має тут деякі слабкі місця. Рамки DI справді допомагають у цій творчій слабкості більше, ніж у власних ін'єкціях. Ви вже знаєте, як це зробити без них. Скільки користі вони вам принесуть, залежить від того, наскільки допомога вам потрібна в будівництві об'єктів.

Існує багато креативних моделей, які вийшли після Банди чотирьох. Конструктор Josh Bloch - чудовий хакер через відсутність названих параметрів Java. Крім цього, є розробники iDSL, які пропонують велику гнучкість. Але кожен із них являє собою значну роботу та котельну плиту.

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

Перш ніж ви занадто закохаєтесь у потужність фреймворків DI, пройдіть певний час та вивчіть інші рамки, які надають вам можливості, які, можливо, можуть вважати, що вам потрібна рамка DI. Багато хто розгалужився поза простими DI . Розглянемо: Lombok , AspectJ і slf4J . Кожен збігається з деякими рамками DI, але кожен працює чудово самостійно.

Якщо тестування дійсно є рушійною силою цього, будь ласка, зверніться до: jUnit (будь-який xUnit насправді) та Mockito (будь-який макет насправді), перш ніж ви почнете думати, що рамки DI повинні перейняти ваше життя.

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


PowerMock вирішив деякі з цих випадків. Принаймні, це дозволяє вам знущатися над статикою
Laiv

Мех. Якщо ви робите DI належним чином, замінити одну рамку IoC Container на іншу слід досить просто. Не тримайте цих приміток від свого коду, і ви будете добре. В основному, використовуйте контейнер IoC, щоб зробити DI, а не використовувати контейнер як сервіс-локатор.
RubberDuck

@RubberDuck правильно. Окрім тестування та постійної підтримки бази даних кодів у кількох рамках DI, чи знаєте ви простий надійний спосіб перевірити, що "ви робите DI правильно"? Навіть якщо я нічого не використовую, ніж pojo's в java, якщо значні зусилля були спрямовані на створення XML, це все ще не проста заміна, коли XML залежить від контейнера IoC.
candied_orange

@CandiedOrange Я використовую "простий" як відносний термін. У грандіозній схемі речей заміна одного кореневого складу іншим - не надто складна задача. Кілька днів працюють вершини. Щодо забезпечення того, що ви робите DI належним чином, саме для цього використовуються Code Reviews.
RubberDuck

2
@RubberDuck Більшість "корінь композиції", які я бачив, - це приблизно 5 рядків коду в основному. Так ні. не надто складне завдання. Це захищений матеріал, який уникає тих рядків, проти яких я попереджую. Ви називаєте це "робити DI належним чином". Я запитую, чи є ви, що б ви використали, щоб довести проблему в огляді коду. Або ти просто сказав "Мех"?
candied_orange

2

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

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

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

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

Але навіть за допомогою DI-рамки ви можете мати центральне місце, наприклад, конфігурація побудови об'єктних графіків (OGCC відтепер), і якщо клас залежить від неоднозначних залежностей, ви можете просто заглянути в OGCC і подивитися, як будується конкретний клас ось там.

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

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

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

Зрештою, швидше за все, все зведеться до того, які ваші уподобання та що ви готові пожертвувати (або час написання фабрик, або прозорість).


Особистий досвід (попередження: суб'єктивне)

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

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


2

Особисто я не використовую DI-контейнери і не люблю їх. У мене є ще кілька причин для цього.

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

Це порушує принципи ООП , такі як згуртованість та метафора об’єкта Лего-цегли Девіда Веста .

Тому будувати весь об’єкт якомога ближче до точки входу програми - це шлях.


1

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

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

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

Однак, немає необхідності в рамках DI.

Але чому ти все-таки хочеш використовувати рамку?

I) Уникайте кодового коду

Якщо ваш проект набуває розміру, де ви знову і знову відчуваєте біль від написання фабрик (і установок), вам слід використовувати рамку DI

II) Декларативний підхід до програмування

Коли Java колись програмувала XML, це тепер: посипання казки анотаціями, і магія відбувається .

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


тл; д-р

Рамки DI не роблять вашу кодову базу частіше кращою, але це допомагає зробити добре виглядає код, який виглядає дійсно чітким . Використовуйте його, коли відчуєте, що вам це потрібно. У певний момент вашого проекту це заощадить ваш час і запобіжить нудоті.


1
Ти правий! Я, як правило, надто переживаю, як все працює під капотом. У мене був жахливий досвід роботи з рамками, які я ледве зрозумів. Я не виступаю за тестування фреймворків, просто розумію, що вони роблять і як це роблять (якщо можливо). Але це залежить від ваших власних інтересів. Я думаю, що розуміючи, як вони працюють, ви в кращому стані вирішити, чи підходять вони вам. Наприклад, таким же чином, як ви порівнювали різні ORM.
Лаїв

1
Я думаю, що завжди правильно знати, як працюють речі під кришкою. Але це не повинно відлякувати вас, не знаючи. Я думаю, що точка продажу для Spring, наприклад, полягає в тому, що вона просто працює. І так, ви абсолютно праві, що для того, щоб прийняти обгрунтоване рішення про те, чи використовувати рамку, ви повинні мати певний ступінь знань. Але я занадто часто бачу схему недовіри до людей, які не мають таких самих шрамів, як себе, хоча не у вашому випадку, де є переконання, до супермаркету може потрапляти лише той, хто зазнав ручного полювання.
Thomas Junk

На щастя, в ці дні нам навіть не потрібні рамки Spring або DI для Java. У нас вже є JSR330, який сумно ігнорується (принаймні, я не бачив проекту, який його реалізує). Отже, люди все ще
встигають

Я відредагував свою відповідь і врахував ваші коментарі. Я усунув «недоліки», пов’язані з налагодженням. Я прийшов до висновку, що ви праві на це. Погляньте і подумайте над оновленням своєї відповіді, тому що зараз ви цитуєте частини, які я видалив зі своєї відповіді.
Лаїв

1
Відповідь змінилася так мало !!! Нічого, що б вас не хвилювало :-). Повідомлення та аргументи залишаються однаковими. Я просто хотів, щоб ваша відповідь і надалі була такою, якою вона є. Я думаю, що вам просто потрібно було зняти одну з лапок.
Laiv

0

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


0

Так, під час роботи в Java я рекомендував би рамку DI. Для цього є кілька причин:

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

  • Анотації на Java надзвичайно корисні та забезпечують відмінний спосіб налаштування залежностей

  • побудова об'єкта java надмірно багатослівна в порівнянні з тим, до чого ви звикли в python; використання рамки тут економить більше роботи, ніж було б в динамічній мові.

  • Кадри java DI можуть робити корисні речі, такі як автоматичне створення проксі-серверів та декораторів, які працюють більше на Java, ніж динамічна мова.


0

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

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

з таким кодом ви можете зробити більше шкоди, ніж користі.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.