:: Не фоксом единым
Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Что такое DI - понятно. А вот при чём тут IoC - так и не пойму. В википедии [url]https://ru.wikipedia.org/wiki/Инверсия_управления[/url] какое то мутное определение "IoC - это принцип". Но, в чём именно заключается этот принцип - не поясняется. В книжке "Spring в действии" (Крейг Уоллс, третье издание) термин "IoC" упомянут два раза - и оба за пределами авторского текста. Т.е. Крейг Уоллс термин IoC не употреблял, полагаю - намеренно.

Так в чём именно заключается инверсия?



Исправлено 1 раз(а). Последнее : S-type, 08.03.18 11:37
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
S-type
Так в чём именно заключается инверсия?

martinfowler.com

IoC это общий принцип - фреймворк крутит основной цикл приложения, вызывая когда надо "прикладной" код. Как для получения визуальной разметки - скажем какие пункты вставить в главное меню, какие текстбоксы вывести в панель при активации модуля "ввод нового клиента", так и для реакции на пользовательские действия (обычная "подписка на события" это тоже вариант IoC).
Без IoC собственно прикладной код "выводит меню, текстбоксы, опрашивает клавиатуру, ловит нажатия мышкой" - вызывая для этого функционал фреймворка. Собственно вот это и есть "инверсия".

DI это просто один из шаблонов реализующих принцип IoC - он конкретно определяет как прикладной компонент получает ссылки на нужные ему другие компоненты (как прикладные, так и системные).

По крайней мере я так это понимаю.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
фреймворк крутит основной цикл приложения, вызывая когда надо

это один конкретный пример. А как "в общем"?

Какой то корявый вопрос, попробую переформулировать.

Что такое зависимость? Объект класса B зависит от объекта класса A, если объект класса B содержит ссылку на объект класса A. Выходит, зависимость - это ссылка на другой объект.

Внедрение зависимости (DI) - это получение ссылки на другой объект откуда то извне (не важно откуда). Когда объект класса B получает ссылку на объект класса А (при этом объект класс А уже создан), и не важно как получает (через конструктор или сеттер) - это и есть "внедрение зависимости". Противоположность внедрению зависимости (отсутствие DI) - когда создание объекта типа А происходит внутри объекта типа В. Судя по всему, в случае DI инверсия заключается в том, что объект типа А создаётся не в объекте типа B, а создаётся где то "во вне" - за пределами объекта типа B. Т.е. объект типа B не причастен к созданию объекта типа A / объект B не контролирует создание объекта А / объект B не управляет созданием объекта типа A. По поводу "во вне". Это может быть как простой код (назовём это ручным внедрение зависимости), так и контекстом Spring (автоматическим внедрением зависимости).

DI - подмножество IoC, относящееся к зависимостям.

IoC - это общий принцип. И этот принцип заключается в том, что _______ - вот тут не могу подобрать слов. К чему ещё применяется IoC, кроме зависимостей?
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
S-type
Igor Korolyov
фреймворк крутит основной цикл приложения, вызывая когда надо
это один конкретный пример. А как "в общем"?
Это как раз "в общем" - фрейморв вызывает прикладной код, а не прикладной код вызывает фреймворк. Т.е. если очень упрощённо, то main это часть фреймворка при инверсии.
S-type
Что такое зависимость?
Тут больше педалируется тот факт что А ЗНАЕТ все подробности про В - собственно говоря потому он и может его создать. В случает DI А не знает ничего про В кроме интерфейса (который, интерфейс этот, описан вообще ВНЕ В). Соответственно реализация В может быть какой угодно (основной рабочий код, специальный какой-то, или вообще тупой mock для тестирования) - и А на это никак не может повлиять. Т.е. речь идёт про "зацепление" aka coupling модулей/классов.
S-type
Судя по всему, в случае DI инверсия заключается в том, что объект типа А создаётся не в объекте типа B, а создаётся где то "во вне" - за пределами объекта типа B.
Да, в коде фреймворка.
S-type
Это может быть как простой код
Если это прикладной код, то это уже не DI...
S-type
IoC - это общий принцип. И этот принцип заключается в том, что _______ - вот тут не могу подобрать слов. К чему ещё применяется IoC, кроме зависимостей?
К общему "потоку управления" программы. Если его контролирует фреймворк, вызывая по необходимости прикладные модули - это IoC. Если его контролирует прикладной код, вызывая для своих нужд функции фреймворка - это "прямой контроль".
В той или иной степени IoC есть практически везде - даже в фоксе, его READ EVENTS и декларативно описанная перед ним система меню - это IoC. Вот FPD-стиль с выводом группы PROMPT-ов, организацией цикла ожидания выбора и потом вызовом нужных процедур в соответствии с выбором - это "прямое управление".


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Если это прикладной код, то это уже не DI...

Почему? Какая разница - кто и где создал другой объект?

Зависимость - это ссылка. Внедрение зависимости - получение ссылки извне. А кто создал объект (на который получена ссылка) - разве это существенно? Разве не может быть DI без IoC?
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Так по теории правильно будет - DI реализуется в IoC контейнере, а не просто прикладной код создающий объекты и связывающий их друг с другом... Вероятно в этом случае таковой код уже не будет "прикладным" - ну, точнее, не ДОЛЖЕН быть прикладным... Обязанность создавать объекты и пропихивать их каким-то потребителям весьма далека от прикладных задач "посчитать скидку" или там "напечатать отчёт об остатках". И по SOLID никак не получится такой класс - контейнер внедрения зависимостей - иметь в прикладном слое приложения.
Я так понимаю что все реализации DI (лично я только с умершим CAB-ом имел дело) основаны на контролируемом создании объектов - т.е. уже изначально речь идёт по какой-то сервис умеющий создавать разнообразные (произвольные) объекты, и пропихивать в них опять же разнообразные (произвольные) ссылки на другие объекты. Назвать такой сервис прикладным как-то язык не поворачивается А если он абсолютно не универсальный, т.е. грубо говоря умеет только ссылку на Logger прописать в свойство Logger трёх заранее известных создаваемых им же классов... Вряд ли это можно назвать полноценным DI Это какая-то специфическая "фабрика", не более того.


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Так по теории правильно будет - DI реализуется в IoC контейнере,

В теории от Мартина Фаулера? Да, в ссылке на статью, что ты привёл:

martinfowler.com
The basic idea of the Dependency Injection is to have a separate object, an assembler, that populates a field in the lister class with an appropriate implementation for the finder interface, resulting in a dependency diagram along the lines of Figure 2

Перевод:
Основная идея внедрения зависимостей состоит в том, чтобы иметь отдельный объект, "Assembler", который заполняет поле в классе lister соответствующей реализацией для интерфейса finder, что приводит к диаграмме зависимостей вдоль линий на рисунке 2

[attachment 29110 injector.gif]

Но, как уже не раз говорил: моё мнение, Фаулер - это балабол, пишущий слишком мутно и с кучей ошибок. Ему нет доверия.

Мне больше нравится такое мнение:

sergeyteplyakov.blogspot.ru
Внедрение зависимостей (DI, Dependency Injection) – это механизм передачи классу его зависимостей.
[...]
Очень важно понимать, что DI-паттерны не говорят, что за зависимость передается, к какому уровню она относится, должна ли быть она у этого класса или нет. Это лишь инструмент передачи зависимостей от одного класса другому.

Т.е. DI - это паттерн. И, ни какого отношения к тому, как создаются объекты, передаваемые по ссылке, данный паттерн не имеет. Можно написать код, применив паттерн DI. При этом внедрение зависимостей будет "ручным". А можно написать код с помощью фреймворка Spring - тогда внедрение зависимостей можно сделать автоматическим. Разве не так?

Igor Korolyov
Я так понимаю что все реализации DI [...] основаны на контролируемом создании объектов
Т.е. ты считаешь, что не может быть DI без IoC. Может, поменяешь мнение?

Igor Korolyov
т.е. уже изначально речь идёт по какой-то сервис умеющий создавать разнообразные (произвольные) объекты, и пропихивать в них опять же разнообразные (произвольные) ссылки на другие объекты.
IMHO, проставлять ссылки в объекты - да, это реализация DI. Но, кто мешает всё делать вручную? Ведь, по сути, Spring -
это код, кем то написанный. Если я напишу код, внедряющий зависимости, разве можно будет сказать - что я не использую DI? Если я не оформлю код, внедряющий зависимости, в виде отдельной библиотеки, разве можно будет сказать - что я не использую DI?

Igor Korolyov
А если он абсолютно не универсальный, т.е. грубо говоря умеет только ссылку на Logger прописать в свойство Logger трёх заранее известных создаваемых им же классов... Вряд ли это можно назвать полноценным DI Это какая-то специфическая "фабрика", не более того.
Вопрос о полноценности - это ведь уже другой вопрос. Тут факт - реализовали DI или нет, вот в чём вопрос. А то, что он реализован только "в узком формате" - это второе.
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Что то мы всё словами, без конкретного кода. Предположим, есть два класса:

public class A {
public void func(){
System.out.println("Hello World");
}
}
public class B {
private A a; // зависимость
public B(){
this.a = new A(); // нет ни какого внедрения
}
public void useA(){
a.func(); // делегирование функционала классу A
}
}

Применим паттерн DI (конкретно, паттерн для внедрения через конструктор). Получим:

public class B {
private A a; // зависимость
public B(A a){ // [2]
this.a = a; // [3]
}
public void useA(){
a.func(); // делегирование функционала классу A
}
}

Класс B принимает в конструкторе ссылку на объект класса A, и эту ссылку сохраняет. Если без Spring-а, то придётся писать:

public class App {
public static void main(String[] args) {
A a = new A(); // вручную создаём объект класса А.
B b = new B(a); // [1]
b.useA();
}
}

Ещё вопрос - а в какой именно момент происходит "внедрение зависимости"? В [1], [2] или [3]? Или, внедрение зависимостей это [1]+[2], или [1]+[3], или только [3] или ещё какая то комбинация?

А вот внедрение зависимости на Spring фреймворке (это работающий код):

import org.springframework.context.annotation.*;
import org.springframework.context.ApplicationContext;
public class App {
@Bean
public A a() {
return new A();
}
@Bean
public B b(A a) {
return new B(a);
}
public static void main (String[] args)
{
ApplicationContext context = new AnnotationConfigApplicationContext(App.class);
B b = context.getBean(B.class); // автоматическое внедрение сильной зависимости
b.useA();
}
}

Автоматическое - потому, что нет кода для получения ссылки на объекта класса A! Непосвящённым кажется, будто тут есть определённая магия. На самом деле магии нет - это связано с тем, что так работает Spring. Если в контексте приложения имеется только один бин типа (класса) A, тогда любой бин, имеющий свойство типа A (в данном случае это параметр конструктора B), будет зависеть именно от этого бина.
Зависимость сильная, потому что создана без использования интерфейса.

Объект b, созданный с помощью фреймвока Spring хоть и называется (в терминах Spring фреймворка) бином, и объект b, созданный без Spring фреймворка (командой new) - это абсолютно одинаковые объекты, это самые обыкновенные объекты Java (POJO). Между ними нет ни какой разницы.

Фреймворк получает управление потоком в моменты вызова AnnotationConfigApplicationContext (создаёт бины) и getBean (возвращает ссылку на нужный бин).

Убедил?



Исправлено 1 раз(а). Последнее : S-type, 10.03.18 12:58
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
S-type
Мне больше нравится такое мнение:
sergeyteplyakov.blogspot.ru
Внедрение зависимостей (DI, Dependency Injection) – это механизм передачи классу его зависимостей.
[...]
Очень важно понимать, что DI-паттерны не говорят, что за зависимость передается, к какому уровню она относится, должна ли быть она у этого класса или нет. Это лишь инструмент передачи зависимостей от одного класса другому.
Тут нет противоречий с Фаулером, хотя это и несколько более широкая трактовка DI.
S-type
Т.е. DI - это паттерн. И, ни какого отношения к тому, как создаются объекты, передаваемые по ссылке, данный паттерн не имеет.
В теории не имеет (т.к. это просто констатация отсутствия зависимости класса от другого класса), на практике - для C# имеет.
S-type
Можно написать код, применив паттерн DI. При этом внедрение зависимостей будет "ручным". А можно написать код с помощью фреймворка Spring - тогда внедрение зависимостей можно сделать автоматическим. Разве не так?
Распространённых IoC контейнеров есть с десяток, не считая самописок. Они все следуют примерно одному и тому же шаблону - и о "ручном коде" ни в одном из них речи не идёт. Т.е. ни один из них реально не знает для каких классов и какие именно зависимости будут внедряться.
S-type
Т.е. ты считаешь, что не может быть DI без IoC. Может, поменяешь мнение?
Если ты сумеешь меня в этом убедить Тут ведь вся фишка как раз в том что внедрение зависимости это и ЕСТЬ IoC, одно из проявлений принципа. Т.е. ты пытаешься изобрести штыковую лопату, которая при этом НЕ будет лопатой
S-type
это код, кем то написанный. Если я напишу код, внедряющий зависимости, разве можно будет сказать - что я не использую DI? Если я не оформлю код, внедряющий зависимости, в виде отдельной библиотеки, разве можно будет сказать - что я не использую DI?
Суть не в том что это отдельная библиотека, и не в том что она написана каким-то Чандрамарапаном и выложена в nuget репозиторий, а не тобой и имеется только в одном твоём проекте (хотя изобретение велосипедов - порочная практика. Лучше уж допилить существующий, чем свой с нуля делать).

Суть в том что это специализированный модуль (обычно это несколько десятков классов) который реализует абстракцию шаблона DI. Т.е. "в итоге" мы получаем при создании объекта класса А наличие в нём ссылки (формально не обязательно "ссылки" - зависимость может быть и не ссылкой на другой объект, но для простоты ограничимся объектами) на некоторый объект реализующий определённый контракт.
Основной плюс будет если класс А зависит от контракта (интерфейса) B, но не зависит от собственно реализующего контракт класса. Потому в общем то и не поощряется внедрение зависимостей с конкретными классами, а не интерфейсами (не все реализации даже позволяют прописывать класс, а не интерфейс для "внедряемой" ссылки).


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Тут нет противоречий с Фаулером, хотя это и несколько более широкая трактовка DI.
Если считать, что Фаулер дал частный "пример", то противоречия нет. А если дал исчерпывающее и законченное определение - то противоречие есть, т.к. в общем случае наличие объекта "Assembler" не обязательно.

Igor Korolyov
S-type
Т.е. DI - это паттерн. И, ни какого отношения к тому, как создаются объекты, передаваемые по ссылке, данный паттерн не имеет.
В теории не имеет (т.к. это просто констатация отсутствия зависимости класса от другого класса), на практике - для C# имеет.
DI - это не констатация отсутствия зависимости. DI - это способ управления зависимостями. И, что подразумевается под "имеет отношение"? В Spring + Java бин - это самый обыкновенный POJO. И, нет разницы - внедрена зависимость вручную или через Spring. В С# разве будет иначе?

Igor Korolyov
S-type
Можно написать код, применив паттерн DI. При этом внедрение зависимостей будет "ручным". А можно написать код с помощью фреймворка Spring - тогда внедрение зависимостей можно сделать автоматическим. Разве не так?
Распространённых IoC контейнеров есть с десяток, не считая самописок. Они все следуют примерно одному и тому же шаблону - и о "ручном коде" ни в одном из них речи не идёт. Т.е. ни один из них реально не знает для каких классов и какие именно зависимости будут внедряться.
Если контейнер действительно НИЧЕГО не знает, то он ни когда ни чего внедрить не сможет. В любом случае контейнер что то знает, и заполнение поля объекта ссылкой на другой объект (т.е. внедрение зависимости) ВСЕГДА будет сопровождаться наличием каких то правил (т.е. знаний, кодом) - в примере выше показал это. То, что контейнер внедряет что то не явно, а с помощью определённых правил (как говорят некоторые "магией Spring") - это всего лишь способ автоматизации сопоставления, но это ни как не способ реализации DI-паттерна.

Igor Korolyov
S-type
Т.е. ты считаешь, что не может быть DI без IoC. Может, поменяешь мнение?
Если ты сумеешь меня в этом убедить Тут ведь вся фишка как раз в том что внедрение зависимости это и ЕСТЬ IoC, одно из проявлений принципа. Т.е. ты пытаешься изобрести штыковую лопату, которая при этом НЕ будет лопатой
Хорошо. Если есть DI, значит уже есть IoC. Но, если есть IoC, то не обязательно это DI. Так?

Но, тогда у меня "рвётся шаблон" в другом месте. Ты говорил, что IoC - это когда фреймворк крутит основной цикл приложения. Но, в том же Spring-фреймворке это не так. Есть контейнер с объектами. Фреймворк создаёт объекты, внедряет в них ссылки, выдаёт объекты "по требованию" в основную программу. При этом фреймворк ни как не "крутит основной цикл приложения". Выходит, Spring - это не Ioc-контейнер?

Igor Korolyov
Суть в том что это специализированный модуль (обычно это несколько десятков классов) который реализует абстракцию шаблона DI. Т.е. "в итоге" мы получаем при создании объекта класса А наличие в нём ссылки (формально не обязательно "ссылки" - зависимость может быть и не ссылкой на другой объект, но для простоты ограничимся объектами) на некоторый объект реализующий определённый контракт.
Почему именно "специализированный модуль"? В чём именно заключена "абстракцию шаблона DI"? Как уже говори, на мой взгляд принцип DI - это то, что "объект, на который внедряется ссылка, создаётся где то вовне". Всё. Это и есть "инверсия управления"! Получая ссылку "из вне" объект не контролирует его создание, по сути - объект "передаёт полномочие на создание объекта" кому то другому. И, не важно, кто этот другой - фреймворк или моя программа. Под "контролирует его создание" подразумевается создание объекта и заполнение его данными (например, через конструктор или сеттеры). Опять таки, не важно - кто создаёт сам объект, в который внедряется ссылка.



Исправлено 3 раз(а). Последнее : S-type, 10.03.18 19:16
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Если так подумать, то в последнем абзаце я ответил на вопрос "что такое инверсия управления" в случае DI.

Пошёл как я в тернажёрный зал...
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
S-type
т.к. в общем случае наличие объекта "Assembler" не обязательно.
Обязательно наличие чего-то, что будет внедрять зависимости (два POCO объекта не могут этого сделать сами по себе). Почему бы эту штуку не называть Assembler? Хотя сейчас более привычно называть это IoC-контейнер.
S-type
DI - это не констатация отсутствия зависимости. DI - это способ управления зависимостями. И, что подразумевается под "имеет отношение"? В Spring + Java бин - это самый обыкновенный POJO. И, нет разницы - внедрена зависимость вручную или через Spring. В С# разве будет иначе?
DI это одна из реализаций принципа IoC, которая в основном служит для устранения "зацепления" классов. "Имеет отношение" - значит что НЕЛЬЗЯ воспользоваться старым добрым var a = new A(); и получить внедрение зависимости в этот самый A (ну на самом деле, конечно, можно - только это будет уже ни разу не классический DI, а какой-то иной шаблон). И да, в шарпе это тоже "обычный POCO" - хотя для некоторых реализаций контейнеров и "декорированный" специальными атрибутами (скажем параметры конструктора, или свойства для хранения ссылок помечаются атрибутами, по которым IoC контейнер понимает что сюда надо прописать ссылку).
"Ручной код" - это половина пути к DI - он не универсален, не гибок, многословен, и потому практически не применим. Как только код становится более-менее универсальным, не зависящим от конкретики связываемых объектов, он тут же превращается в реализацию DI
S-type
Если контейнер действительно НИЧЕГО не знает, то он ни когда ни чего внедрить не сможет.
Отчего же? В "тупом" варианте он вполне себе может и абсолютно ничего не знать о связываемых POCO объектах. Через рефлексию получить все описанные в сборке (или всех загруженных сборках) типы (словарик "что мы умеем внедрять"), для запрашиваемого типа просмотреть все его свойства (к примеру), или все параметры конструктора (это ещё более тупой вариант, хотя тогда параметризованный конструктор должен быть всего один - иначе "внедрятель" не будет знать какой именно использовать), и создать экземпляр, попутно создав по экземпляру на каждый найденный "требуемый тип" (а т.к. он "тупой", то всё то же самое должен будет проделать и для создаваемых "зависимых" объектов - главное тут не попасть в цикл, или уметь обходить его - скажем подсовывая ссылку на УЖЕ созданный экземпляр).
S-type
В любом случае контейнер что то знает, и заполнение поля объекта ссылкой на другой объект (т.е. внедрение зависимости) ВСЕГДА будет сопровождаться наличием каких то правил
Как правило это так - контейнер тем или иным способом узнаёт о "правилах" ("тупой" контейнер как описано выше практически бесполезен - с ним придётся лишь бороться, а не облегчать себе жизнь). Может явно через код типа "для свойств типа IOne подставлять экземпляр типа OneImplementation", может опосредованно - "для свойств помеченных атрибутом [ServiceDependency(typeof(IOne))] подставлять экземпляр типа помеченного атрибутом [Service(typeof(IOne))]". Конечно же "работать" эту кухня будет только если экземпляр запрошен у контейнера, а не создан прямым вызовом new A();
S-type
Но, если есть IoC, то не обязательно это DI. Так?
Не обязательно. Скажем для той же самой цели устранения "зацепления" классов может применяться шаблон ServiceLocator. Впрочем даже и безо всяких "устранений зависимостей" можно использовать другие IoC моменты - т.к. это очень широкий подход.
S-type
Ты говорил, что IoC - это когда фреймворк крутит основной цикл приложения.
И это ТОЖЕ. IoC это принцип "переворачивания контроля", он может применяться в самых разных местах ПО для самых разных целей. IoC-контейнер - только один из аспектов IoC как принципа.
S-type
Почему именно "специализированный модуль"? В чём именно заключена "абстракцию шаблона DI"? Как уже говори, на мой взгляд принцип DI - это то, что "объект, на который внедряется ссылка, создаётся где то вовне". Всё.
Нет не всё. А собственно "внедрение ссылки"? То что объект создан снаружи - пол дела. Он и для обычного синглтона "создан снаружи", и для "фабрики" тоже, только там не идёт речи о DI.
S-type
Получая ссылку "из вне" объект не контролирует его создание, по сути - объект "передаёт полномочие на создание объекта" кому то другому.
Не только создание, но и получение ссылки! Именно потому и создаваться объект должен не напрямую, а через механизмы соответствующего IoC-контейнера, иначе каким волшебным образом ссылка попадёт к этому самому объекту?
S-type
И, не важно, кто этот другой - фреймворк или моя программа. Под "контролирует его создание" подразумевается создание объекта и заполнение его данными (например, через конструктор или сеттеры). Опять таки, не важно - кто создаёт сам объект, в который внедряется ссылка.
Почему ты считаешь что "твоя программа" это 100% прикладной код? Если там есть модуль создающий объекты и прописывающий в них ссылки - т.е. выполняющий функции IoC-контейнера, то это как раз и есть СИСТЕМНЫЙ код - хотя и написан он тобой.
И да, ВАЖНО кто создаёт объект. Нет возможности передать ссылки в конструктор объекта если не этот же самый код (который должен прописать ссылки) и создаёт этот объект! Даже для внедрения через свойства это важно, т.к. ссылки должны быть заполнены тотчас же после создания объекта - а не "когда-то там потом другим кодом". У внедрения через конструктор есть одно важное преимущество - можно пользоваться "внедрёнными сервисами" уже во время инициализации объекта - все прочие способы не позволяют этого добиться. Но они должны обеспечить такое поведение, что в "прикладном" коде, вызвавшем var a = IoCContainer.Get<A>(); уже сразу же в следующей строке кода можно без ошибок воспользоваться a.SomeMethodUsingInjectedService(); Т.е. все зависимости уже внедрены. И внедрены они именно где-то внутри IoCContainer.Get<Type>() - а это как раз и есть "системный" код, даже если этот класс написал ты сам (хотя смысла в этом лично я не вижу).
Код вида
var a = new A();
a.ServiceB = new BImpl();
a.SomeMethodUsingServiceB();
НЕ является примером DI - хотя строго формально класс А не связан с классом B, не создаёт его экземпляр (и даже не в курсе какую реализацию будет использовать, если свойство имеет тип интерфейса). Поскольку прикладной "код использования" совмещён с "кодом внедрения зависимости".
Убери 2 первые строки в специальный класс - и получишь DI, хоть и дубовый, "ручной"


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Код вида
var a = new A();
a.ServiceB = new BImpl();
a.SomeMethodUsingServiceB();
НЕ является примером DI - хотя строго формально класс А не связан с классом B, не создаёт его экземпляр (и даже не в курсе какую реализацию будет использовать, если свойство имеет тип интерфейса). Поскольку прикладной "код использования" совмещён с "кодом внедрения зависимости".
Убери 2 первые строки в специальный класс - и получишь DI, хоть и дубовый, "ручной"
Вот тут не согласен категорически. Данный пример (весь, целиком) - это и есть самое непосредственное "внедрение зависимости", зависимость внедряется через свойство (сеттер).

"Зависимость" - это "ссылка", "внедрение" - это "получение извне". Вывод - внедрение зависимости, это получение ссылки на объект откуда то извне. И, кто создал объект, на который получена ссылка - к DI отношения не имеет.

Начал гуглить и нашёл habrahabr.ru , конкретно - абзац "Объяснение внедрения зависимостей".



Исправлено 1 раз(а). Последнее : S-type, 11.03.18 19:39
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Ну так почитай дальше, там всё разжёвано, почему ПЛОХО писать код типа
var a = new A();
a.ServiceB = new BImpl();
a.SomeMethodUsingServiceB();
или, что то же самое по сути
var a = new A(new BImpl(new CImpl(), new DImpl(new XYZImpl()),...));
a.SomeMethodUsingServiceB();
И зачем нужны контейнеры всю эту кухню (как "создания", так и "внедрения") убирающие из прикладного кода.
P.S. И про "зависимости" в начале цикла внимательно почитай - а то ты, видимо, полагаешь что написав
class Foo
{
Bar barImpl;
Foo (Bar impl)
{
barImpl = impl;
}
}
ты "избавился от зависимости" в классе Foo от класса Bar - хотя это ну абсолютно не так, и даже заменив код на
class Foo
{
IBar someBarImpl;
Foo (IBar impl)
{
someBarImpl = impl;
}
}
ты всего лишь заменяешь зависимость от класса на зависимость от интерфейса (это уже очень хорошо и правильно, но таки "зависимость" остаётся).


------------------
WBR, Igor




Исправлено 1 раз(а). Последнее : Igor Korolyov, 11.03.18 20:13
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Ну так почитай дальше, там всё разжёвано, почему ПЛОХО писать код типа
var a = new A();
a.ServiceB = new BImpl();
a.SomeMethodUsingServiceB(); // внедрение зависимости
Вопрос не в качестве кода. Вопрос в том, что в этом коде есть внедрение зависимости. И, для DI наличие отдельного специального класса "Assembler" совсем не обязательно. Убедил?

Igor Korolyov
И зачем нужны контейнеры всю эту кухню (как "создания", так и "внедрения") убирающие из прикладного кода.
Зачем нужны контейнеры - это уже следующий вопрос. Как уже писал, с помощью контейнера можно автоматизировать сопоставление параметров классов и их зависимостей (и даже пример на Java+Spring привёл). Но, прежде чем за Spring браться, надо же понять - что такое DI

Igor Korolyov
P.S. И про "зависимости" в начале цикла внимательно почитай - а то ты, видимо, полагаешь что написав
[...]
ты всего лишь заменяешь зависимость от класса на зависимость от интерфейса (это уже очень хорошо и правильно, но таки "зависимость" остаётся).
Ну, зачем, дорогой, наговариваешь? Я же выше по русски написал:

S-type
Зависимость сильная, потому что создана без использования интерфейса.
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Нет не убедил. Для меня DI всегда неразрывно связан с тем или иным IoC контейнером внедряющим зависимости и, соответственно, конструирующим объекты. Без него я лично никакого DI не вижу (так же как и ООП в VBA, например - хотя там и "свойства" и "объекты" имеют место быть). По крайней мере в шарпе. Т.е. по моему мнению в приведенных примерах только явовский вариант имеет DI.
И, насколько я понимаю, не я один такой


------------------
WBR, Igor
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Т,е. твоё мнение, что для реализации DI-паттерна наличие специального класса "Assembler" (упомянутого в статье Мартина Фаулера) обязательно. У меня мнение - специальный класс "Assembler" для реализации паттерна DI не требуется.

Моё определение "внедрение" - это "получение извне". Твоё определение термина "внедрение" - это "получение от контейнера DI".

И, как можно видеть, можно найти ссылки подтверждающие как твоё мнение, так и моё.

Думаю, пора ставить точку.
Ratings: 0 negative/0 positive
Re: Инверсия управления
Igor Korolyov

Сообщений: 34580
Дата регистрации: 28.05.2002
Так уже ж
У меня нет большого опыта в DI - кроме CAB-овского ObjectBuilder-а вкупе с другими MS patterns & practices наворотами (а там их ну очень много - их фреймворк это нечто - при том что по сути он никогда и не был доведен до стадии "зрелого продукта" - хотя из него "выросли" Unity и Prism - жаль последний это WPF) я ничего реально не использовал. Но оно померло уж давно (а проект с их использованием нет ) потому совсем недавно я и озаботился поиском/выбором более современных IoC средств (для начала хотя бы эту часть, уж про UI с каким MVP подходом да REST сервисы со стыковкой для десктопа пока совсем рано думать).
И то что я видел - ну "как под копирку" Потому я и говорю что это не только моё личное мнение... Хотя, конечно же, в первую очередь личное.

P.S. Если забыть про "теорию", то что будет "на практике" применимо к C#?
Unity, Ninject, Castle Windsor, StructureMap, Spring.NET, Autofac... Достаточно бегло взглянуть на них, чтобы понять общий принцип.

Ну и цитата из www.dotnettricks.com
Цитата:
We can also manage an application dependencies without a DI Container, but it will be like as POOR MAN’S DI and we have to do more work, to make it configured and manageable.


------------------
WBR, Igor




Исправлено 1 раз(а). Последнее : Igor Korolyov, 12.03.18 00:33
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Мне не довелось дожить до DI в C#. Java всё больше проникает в мои мозги, которые сопротивляюсь этому отсталому языку. Шучу. Не критично, но хватает некоторых мелочей (например, out-параметров). После JavaFX (идеология чем то похожа на VPF) изучаю ServiceMix, а это Karaf. Как написано на karaf.apache.org Programming Model (Spring / BluePrint / DeclarativeService). Вот, и полез копать Spring.

Конечно, ситуация не такая критичная, как с зоопарком MV*, но всё равно - много противоречий, что бы всё "уложилось" в голову. В той же "Spring в действии" Крейга Уоллса на странице 36 он пишет:

Цитата:
...благодаря DI объекты получают свои зависимости во время создания от некоторой третьей стороны, координирующей работу каждого объекта в системе.

Что может "координировать работку каждого объекта в системе"? Понятно, что это может быть "контейнер". Но, [почему?] не сказано же явно, что "контейнер", а как то аморфно "третья сторона". От и гадай - что это. А мнения, увы, разделились.



Исправлено 1 раз(а). Последнее : S-type, 12.03.18 01:18
Ratings: 0 negative/0 positive
Re: Инверсия управления
S-type
Автор

Сообщений: 2969
Дата регистрации: 24.04.2004
Igor Korolyov
Ну и цитата из www.dotnettricks.com
Цитата:
We can also manage an application dependencies without a DI Container, but it will be like as POOR MAN’S DI and we have to do more work, to make it configured and manageable.

Что в переводе:

Цитата:
Мы также можем управлять зависимостями приложений без контейнера DI, но это будет похоже на БЕДНОГО ЧЕЛОВЕКА DI, и мы должны сделать больше работы, чтобы сделать его настроенным и управляемым.

Т.е. проводится разница между "управлением зависимости" и "внедрением зависимости".



Исправлено 1 раз(а). Последнее : S-type, 12.03.18 09:43
Ratings: 0 negative/0 positive


Извините, только зарегистрированные пользователи могут оставлять сообщения в этом форуме.

On-line: 9 (Гостей: 9)

© 2000-2024 Fox Club 
Яндекс.Метрика