А как насчет других языков? Можно ли использовать DI без управляемой кучи?
Наличие управляемого кучи не является обязательным условием для DI. C++, например, не является управляемым языком, но для него существуют рамки DI, сопоставимые по функциональным возможностям с фреймами DI для управляемых языков, таких как Java или C#.
Отличная презентация Daniele Pallastrelli Going native with less coupling - Dependency Injection in C++ подробно объясняет преимущества DI над двумя другими способами развязки (фабрики и сервисные локаторы). Он также представляет собой инфраструктуру C++ DI под названием Wallaroo и объясняет ее внутренности.
Еще одна инфраструктура C++ DI, основанная на другом подходе, тогда Wallaroo является [Boost].DI. Я настоятельно рекомендую прочитать главу «Введение». Он дает короткие, но хорошие ответы на такие вопросы, как «Я использую инъекцию зависимостей уже?», «Нужен ли мне инъекционный подход?» И т. Д.
Третья структура C++ DI, которую я хочу упомянуть, это Infector++.
Это всего лишь три из многих структур C++ DI там. Вы можете найти множество из них, перечисленных на this page.
Моя точка, если есть так много рамок DI для C++, независимо от того, если они широко приняты или нет, это, конечно, можно иметь DI без управляемой кучи :-)
Если да, то какие шаблоны кода работают хорошо, чтобы гарантировать, что ресурсы будут выпущены правильно?
В приведенных выше ссылках содержится дополнительная информация о том, как полная реализация ЦС может быть выполнена на C++, включая разрешение зависимостей, различные политики создания и области объектов и, наконец, ваш вопрос - управление жизненным циклом объекта.
Здесь я просто набросаю общую идею на , как управление жизненным циклом может быть последовательно и детерминированным образом.. Все упомянутые структуры сильно используют интеллектуальные указатели (std::unique_ptr
, std::shared_ptr
, также boost::shared_ptr
, если они предоставляют поддержку Boost) и приложить к ним семантику политики создания. Обратите внимание, что вам не нужен полноразмерный DI-каркас для использования этого шаблона. Основная идея очень проста.
Пусть я объявить класс как следующему:
class i_depend_on_others {
i_depend_on_others(std::unique_ptr<other>,
std::shared_ptr<another_other>,
boost::shared_ptr<yet_another_other>)
{ }
};
Это явный конструктор инъекция, но с дополнительным семантическим об ожидаемом время жизни «других». Первый other
будет принадлежать экземпляру i_depend_on_others
, и поскольку у нас есть std::unique_ptr
, он будет удален, как только экземпляр i_depend_on_others
будет удален. Ожидается, что another_other
и yet_another_other
имеют жизненный цикл, не зависящий от экземпляра i_depend_on_others
. Этот шаблон четко определяет, когда является экземпляром i_depend_on_others
, ответственным за очистку ресурса, и когда код вызова должен это сделать. (В случае рамки DI, рамка заботится о общих случаях.)
Вопрос заключается в том, что делать в этом случае:
class i_depend_on_others_as_well {
i_depend_on_others_as_well(other*) { }
};
(я опущу здесь спорить, что сырые указатели должны избегайте в современной разработке на C++. Скажем, мы вынуждены их использовать.) Опять же, шаблон определяет четкую семантику. Необработанный указатель означает передачу прав собственности. Экземпляр i_depend_on_others_as_well
несет ответственность за удаление other
.
В случае каркасов DI, таких как [Boost].DI, тип указателя будет определять жизненный цикл по умолчанию введенных объектов. Для указателей на общий доступ они будут одноязычными, создаваться один раз и поддерживаться с помощью [Boost] .DI, а для сырых указателей и уникальных указателей каждый раз будет создан новый экземпляр.
Более подробное объяснение этого шаблона можно найти в главе "Decide the life times" документации [Boost] .DI.
Да, вы можете просто уничтожить введенный объект, когда экземпляр класса будет уничтожен. –
В управляемой и неуправляемой среде это [Корень композиции] (http://blog.ploeh.dk/2011/07/28/CompositionRoot/), который контролирует создание и детерминированную очистку ресурсов. В неуправляемых средах это просто означает немного больше работы, но по-прежнему является составным корнем, который отвечает за создание этих компонентов и освобождает их память. – Steven