2017-02-04 12 views
2

С помощью инъекции зависимостей экземпляр класса определяется и передается пользователем, часто как аргумент конструктора. Это хорошо работает на языках с управляемой кучей, поскольку нет необходимости беспокоиться о завершении срока службы зависимостей. Но как насчет других типов языков?Возможна ли DI без управляемой кучи?

Например, в традиционной среде malloc и free метод, который выделяет память, обычно должен также освобождать его. Я не уверен, как это будет достигнуто с DI.

Или с схемой памяти, которая требует подсчета ссылок, например. COM, я не уверен, когда вызывающий абонент вызовет Release на зависимости, или если объект, который получает инъекцию, должен дважды позвонить Release.

Можно ли использовать DI без управляемой кучи? Если да, то какие шаблоны кода работают хорошо, чтобы гарантировать, что ресурсы будут выпущены правильно?

+0

Да, вы можете просто уничтожить введенный объект, когда экземпляр класса будет уничтожен. –

+0

В управляемой и неуправляемой среде это [Корень композиции] (http://blog.ploeh.dk/2011/07/28/CompositionRoot/), который контролирует создание и детерминированную очистку ресурсов. В неуправляемых средах это просто означает немного больше работы, но по-прежнему является составным корнем, который отвечает за создание этих компонентов и освобождает их память. – Steven

ответ

1

А как насчет других языков? Можно ли использовать 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.

1

Для меня DI и сбор мусора не связаны. Вам просто нужно организовать управление памятью. Начните с попытки использовать статические объекты повсюду. Это будет работать, если ваш график DI статичен (т. Е. Он не изменяется во время работы приложения).

Если ваш график DI развивается или его структура определяется во время запуска приложения, больше информации о том, как вы это делаете. Я не уверен, что общее решение, которое подходит для каждого случая, возможно. Объект, который изменяет график DI, должен отвечать за очистку. Точно так же, как это делается на C++ в других случаях. Например, вы можете поместить объекты прокси-сервера DI в статический контейнер, который будет уничтожен (и если все правильно организовано его содержимое также) в конце работы приложения.

В управлении памятью C/C++ необходимо так или иначе управлять контейнерами, соединениями и другими вещами. Я не понимаю, почему DI является особенным. Сбор мусора решает управление памятью (все еще имеет свои недостатки) для всего, для чего он используется.