Russian Qt Forum
Апрель 30, 2024, 05:14 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Dependency injection  (Прочитано 19331 раз)
once_again_abc
Гость
« : Август 26, 2014, 09:51 »

Посоветуйте хорошее описание паттерна (см. сабж) на С++ с хорошими примерами.
Записан
once_again_abc
Гость
« Ответ #1 : Август 28, 2014, 02:58 »

такой хороший форум, а программистов на С++ нет  Злой Обеспокоенный В замешательстве Плачущий
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Август 28, 2014, 07:30 »

Цитировать
Если, по вашему мнению, ответа долго нет, оскорбитесь, написав что-то в духе: я думал здесь умеют решать, а тут такие же бараны как я.
Улыбающийся
Записан
Bepec
Гость
« Ответ #3 : Август 28, 2014, 07:48 »

http://vladimirsblog.com/laravel-dependency-injection-for-beginners/ не подойдёт?

Кстати я почитал, не до конца понял принцип. Получается мы отказываемся от ООП в пользу процедурного подхода для лучшей реализации в тестах?
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #4 : Август 28, 2014, 22:48 »

http://vladimirsblog.com/laravel-dependency-injection-for-beginners/ не подойдёт?
Кстати я почитал, не до конца понял принцип. Получается мы отказываемся от ООП в пользу процедурного подхода для лучшей реализации в тестах?

Нет. Вы отказываетесь от практичного ООП в пользу ООП гловного мозга.

Иньекция зависимостей - анти-паттерн, как сделать простое более сложным.
Записан
once_again_abc
Гость
« Ответ #5 : Август 29, 2014, 02:13 »

http://vladimirsblog.com/laravel-dependency-injection-for-beginners/ не подойдёт?

Кстати я почитал, не до конца понял принцип. Получается мы отказываемся от ООП в пользу процедурного подхода для лучшей реализации в тестах?



вот поэтому я и прошу поделиться информацией - чтобы знать ответы на такие вопросы. знаю что DI штука очень мощная и полезная, особенно в языках, где есть сборщик мусора. знать и применять этот супермегапаттерн is a must для любого нормального инженера.
Записан
Bepec
Гость
« Ответ #6 : Август 29, 2014, 08:06 »

Насколько мне видится тут наоборот идёт странное влечение от простого к сложному + разбрасываем сущности налево направо. Ну да ладно, надеюсь когда вы доберётесь до истины, вы поведаетё и нам.
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #7 : Август 30, 2014, 15:26 »

Читнул по диагонали, в общем-то обычный код, я так и пишу. Теперь буду знать, что это оказывается ПАТТЕРН, ёпта.

То есть там сперва приводят пример быдлокода, потом нормальный, типа паттерн применили.

Ну да ладно.
Записан

Гугль в помощь
Bepec
Гость
« Ответ #8 : Август 30, 2014, 15:54 »

На мой взгляд бессмысленное раскидывание сущностей или неудачный пример.

Если нужен метод только сохраняющий новую книгу в одну бд - то зачем его менять? Вот он, создаёт новую книгу и пихает в базу.

Конечно если мы рассчитываем на дальнейшее, можно строить архитектуру, разбросать на базу/драйвер/сохранение/книгу/заглавие/главы/строчки. Но просто так это делать?

Было
Код:
$bookStorage = new BookStorage;
$bookStorage->store('Фёдор Михайлович Достоевский', 'Идиот');

Стало
Код:
$book = new Book;
$book->author = 'Фёдор Михайлович Достоевский';
$book->title = 'Идиот';

$database = new Database;

$bookStorage = new BookStorage($database);
$bookStorage->store($book);

На мой взгляд это головная боль дальнейшей разработки, весь контроль ложится на программиста, плодятся кучи сущностей. А если классов не 3, а 15?
Вместо читабельного кода появляется мусорная куча. Добавляем обработку ошибок и... И всё ещё хуже, ибо обработку тоже напишем в этом стиле, то вместо 2 строк получим 100500.

Инкапсуляция должна быть.
Записан
vregess
Гость
« Ответ #9 : Август 30, 2014, 16:01 »

Можешь посмотреть
http://adam.younglogic.com/2008/07/dependency-injection-in-c/
http://stackoverflow.com/questions/4469304/dependency-injection-framework-for-c (включает в себя первую ссылку).

Я имел дело с DI лишь однажды на нескольких AS3 проектах, использовал фреймворк robotlegs (и, возможно, еще на java с ее guice). Да, вещь удобная при определенных условиях.
В первом приближении можно рассматривать DI как фабрику объектов, которая разруливает зависимости создаваемых объектов. Можно удобно менять реализации (на пример, для тестов использовать другие классы/объекты). Все это можно сделать руками, ну а тут как бы паттерн, и ты уже не просто инженер, а "нормальный".

После as3 проектов искал что-то похожее и на с++, помню первую ссылку и читал или что-то сильно похожее. Даже пробовал использовать. В результате отказался, т.к. мне показалось что нормальная реализация DI, которая не усложнит проект, возможна только при вменяемой поддержке интроспекции в языке. Навроде java (там есть Guice) или питона. Ну а в с++, где с этим проблемы, можно наворотить такого, что потом не разгребешь.

Причем тут сборщик мусора, не понял.

В общем в мире с++ реализации есть, но они не на столько хороши, как в других языках, и пока вряд ли будут.

PS to Верес.
весь контроль ложится на программиста

Как раз наоборот, все за тебя сделает DI фреймворк, и никаких раскидываний сущностей. Пример и правда не особо.

Если есть прям не преодолимое желание разобраться с dependency injection, то лучше смотреть реализации для других языков (java, as3, c#), где есть нормальные фреймворки.
Записан
_Bers
Бывалый
*****
Offline Offline

Сообщений: 486


Просмотр профиля
« Ответ #10 : Август 30, 2014, 17:09 »

На мой взгляд бессмысленное раскидывание сущностей или неудачный пример.

Первое.
Скажем так: удачных примеров я почему то ни разу не наблюдал.
Адепты о них почему то молчат. Подозреваю - сами не знают.


На мой взгляд это головная боль дальнейшей разработки, весь контроль ложится на программиста, плодятся кучи сущностей. А если классов не 3, а 15?
Вместо читабельного кода появляется мусорная куча. Добавляем обработку ошибок и... И всё ещё хуже, ибо обработку тоже напишем в этом стиле, то вместо 2 строк получим 100500.

Инкапсуляция должна быть.

О том и речь: ооп ради ооп есть ооп головного мозга.

Фишка этого анти-паттерна в том, что вы можете встретить кучку людей, заявляющих "это круто". Но ни один из них не сможет привести ни одного реального примера, который иллюстрирует профит.

Записан
Bepec
Гость
« Ответ #11 : Август 30, 2014, 17:36 »

А я верил что оно полезное. Даже гуглил :/ Какое разочарование.

to ck: Я вижу вы в теме, давайте поговорим.

1) Основная суть паттерна - раскидывание задачи на подзадачи + возможность на место любого объекта подставить другой, так?
2) Это решается просто зависимостями класса. Т.е. вместо
Код:
$book = new Book;
$book->author = 'Фёдор Михайлович Достоевский';
$book->title = 'Идиот';

$database = new Database;

$bookStorage = new BookStorage($database);
$bookStorage->store($book);
можно спокойно написать
Код:
book::book(string inAuthor, string inTitle, BookStorage * inStore = 0, Database * inBase = 0)
,author(inAuthor)
,title(inTitle)
{
store = inStore;
base = inBase;
}

И в результате получаем ту же зависимость по смыслу, но более ООП-шную и разруливаемую классом. Разница на мой взгляд просто в порядке инициализации.

В чем преимущество паттерна? В чем плюсы?


update: написал, прочитал и понял что единственно - мы фиксируем архитектуру без этого паттерна. Т.е. зависимость прямая. Но это несущественно.

Судя по всему неудачность именно в примере. А паттерн просто неразрывно связан с ООП, т.е. имеет ту же цель - разбиение на подзадачи. Таким образом он скорее часть ООП как паттерна программирования.
« Последнее редактирование: Август 30, 2014, 17:48 от Bepec » Записан
vregess
Гость
« Ответ #12 : Август 31, 2014, 18:59 »

1) Основная суть паттерна - раскидывание задачи на подзадачи + возможность на место любого объекта подставить другой, так?

Не так. Его задача сделать классы менее связанными друг с другом (как и многих других паттернов), чтобы использующий класс, не отвлекался на создание используемого класса.

В твоем примере основная идея не в классе Book, он тут как некие данные, которыми просто оперируют. Все начинается там, где появляется Database. Изначально мы имеем (сокращенный пример из того поста):

Код
PHP
class BookStorage
{
   private $db;
   public function __construct()
   {
       $this->db = new Database;
       // or
       //$this->db = Database::getInstance()
   }
 
   public function store(Book $book)
   {
       $this->db->insert(book);
   }
}
 
 

Здесь BookStorage зависит от Database, тк явно создает его в своем конструкторе. Из-за этого мы не сможем поменять Database на другую реализацию. Поэтому мы добавляем аргумент в конструктор, чтобы передать уже сконструированный Database:

Код
PHP
class BookStorage
{
   private $db;
   public function __construct(Database db)
   {
       $this->db = db;
   }
 
   public function store(Book $book)
   {
       $this->db->insert(book);
   }
}
 

Вуаля. Мы сделали внедрение зависимости. За громким названием скрывается достаточно простой принцип. Мы "засовываем" один объект внутрь другого, внедряем его. Мы внедряем объект, от которого зависит BookStorage.

Получаем, классу BookStorage больше не нужно создавать Database самостоятельно, он просто им пользуется, и мы легко можем менять реализации Database. Надеюсь, разжевывать преимущества второго подхода над первым не нужно. Вот об этом и был тот пост. Он просто проиллюстрировал один из вариантов внедрения зависимости (внедрение зависимости через конструктор).

Где здесь анти-паттерн?

Это что касается того конкретного примера, по ссылке Вереса, который не понятно почему был приведен, наверное первая попавшаяся ссылка. Ну да ладно.

Разберемся по-быстрому с инверсией управления (Inversion of Control, IoC).
По названию совсем не ясно, что за этом стоит, по крайней мере для меня, не ясно, зачем так назвали. Цель - тоже уменьшить связанность между классами (сущностями). На примере BookStorage и Database. Здесь Database - это конкретная реализация хранилища, Получаем, что BookStorage может работать только с базой данных. BookStorage тесно связан с базой данных, как хранилищем. Сейчас мы поменяем зависимости путем введения новой сущности - интерфейс хранилища. Пример вперемешку с с++, т.к. я php не знаю.

Код
PHP
class IStorage {
   virtual void insert(Book);
}
 
class Database: public IStorage {
   virtual void insert(Book) {...}
}
 
class BookStorage
{
   private $db;
   public function __construct(IStorage db)
   {
       $this->db = db;
   }
 
   public function store(Book $book)
   {
       $this->db->insert(book);
   }
}
 

Теперь BookStorage зависит от абстракции IStorage, а не от конкретной реализации. Этот подход и называют инверсия управления.

Теперь у нас есть 2 подхода - внедрение зависимости и инверсия управления.
Используя их мы можем создать так называемый IoC-контейнер, который по сути является фабрикой объектов (фабрика - опять не совсем понятное название паттерна, пусть будет Создаватель)
и содержит в себе знания, как эти объекты создавать и разруливать зависимости, если надо. Изначально мы создаем конфигурации для разных объектов, а потом по запросу IoC контейнер нам создает объекты.

Навроде:
Код
C++ (Qt)
ioc.forClass(IStorage).create(Database);
 

Пример с зависимостями может выглядеть как:

Код
C++ (Qt)
class Database {
   Database(One a, Two b) { ... }
   ...
}
 
ioc.forClass(IStorage).create(Database);
ioc.forClass(One).create(OneStuff);
ioc.forClass(Two).create(AnotherStuff);
 

Мы не указываем, как создавать Database, IoC сам все разрулит. Либо конфигурация задается отдельным файлом типа XML.
Далее мы просим у IoC создать для нас объекты:
Код
C++ (Qt)
db = ioc.get(IStorage)
 

В некоторых реализациях процесс запросов к IoC-контейнеру происходит автоматически. На пример, в robotlegs мы помечаем атрибут класса, и ему присваивается значение автоматически.

Код
C++ (Qt)
class Bla {
   [Inject]
   public Database storage;
 
   ...
   storage.insert(book);
}
 

Все это похоже на фабрику объектов, разница в том, что фабрики ты пишешь сам, а тут делается за тебя.
Хорошо сказано тут:
Цитировать
When using a factory your code is still actually responsible for creating
objects. By DI you outsource that responsibility to another class or a
framework, which is separate from your code.
(Переводим самостоятельно).

Вот в принципе так, вкратце.

Для закрепления основ можно почитать серию постов:
http://www.apofig.com/2010/08/dependency-injection-inversion-of.html
http://www.apofig.com/2011/07/dependency-injection-inversion-of.html
http://www.apofig.com/2011/07/dependency-injection-inversion-of_13.html
http://www.apofig.com/2011/07/dependency-injection-inversion-of_23.html
http://www.apofig.com/2011/10/dependency-injection-inversion-of.html
http://www.apofig.com/2012/03/java-for-fun-dependency-injection.html

примеры на java, но разберешься - тыжпрограммист.



Записан
Bepec
Гость
« Ответ #13 : Август 31, 2014, 19:39 »

Хотя в принципе неважно, принцип я уловил.

Кратко: мы перекладываем контроль над модулями в левый класс, создавая прослойку с собственными параметрами.

Таким образом мы увеличиваем гибкость системы, но получаем в нагрузку перегруженный класс, который знает всё о всех.
Гибкость ещё бОльшая, чем можно добиться в классе, но усложняет структуру на порядок.

В принципе обычная фабрика, только не классов, а модулей для классов.

Так то плюсов не видно, минусы - класс всё обо всём.

Печально и неоднозначно.

« Последнее редактирование: Август 31, 2014, 19:41 от Bepec » Записан
vregess
Гость
« Ответ #14 : Сентябрь 01, 2014, 06:01 »

Похоже суть ты не особо уловил, но раз в принципе не важно, то  и не важно.
Если нет понимания, как и где применять инструмент, то лучше его не использовать.
Просто обходи его стороной, тем более на с++.
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.221 секунд. Запросов: 23.