В чем разница между инверсия управления и внедрение зависимостей в C++?

Я недавно читал о DI и IoC на C++. Я немного смущен (даже после прочтения связанных вопросов здесь на SO) и надеялся на некоторые разъяснения.

мне кажется, что знакомство с STL и Boost приводит к использованию инъекции зависимостей совсем немного. Например, предположим, я сделал функцию, которая нашла среднее значение диапазона чисел:

template <typename Iter>
double mean(Iter first, Iter last)
{
    double sum = 0;
    size_t number = 0;
    while (first != last)
    {
        sum += *(first++);
        ++number;
    }
    return sum/number;
};

это (т. е. использование итераторов вместо доступа к самой коллекции) зависимость инъекция? Инверсия контроля? Ни?

давайте рассмотрим другой пример. У нас есть класс:

class Dice
{
public:
    typedef boost::mt19937 Engine;
    Dice(int num_dice, Engine& rng) : n_(num_dice), eng_(rng) {}
    int roll()
    {
        int sum = 0;
        for (int i = 0; i < num_dice; ++i)
            sum += boost::uniform_int<>(1,6)(eng_);
        return sum;
    }
private:
    Engine& eng_;
    int n_;
};

Это похоже на инъекцию зависимостей. Но является ли это инверсией контроля?

кроме того, если я что-то упускаю, может кто-то помочь мне? Это кажется естественным способом делать вещи, так что если это все, что нужно для инъекции зависимости, почему людям трудно ее использовать?

2 ответов


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

инверсия управления и итерационные

в этом случае "управление "означает" управление потоком".

Я думаю, что ваш первый пример с итерацией на самом деле не инверсия управления, потому что этот код явно выполняет управление потоком. Инверсия контроль будет отделять действие от потока управления. Это может выглядеть так (Простите мою java / C#):

SumVisitor sumVisitor = new SumVisitor();
collection.AcceptVisitor(sumVisitor);
int sum = sumVisitor.GetSum();

объект visitor делает что-то для каждого элемента коллекции, который он посещает, например, обновляет поле счетчика сумм. Но у него нет управления как или когда он вызывается на коллекции, поэтому инверсия управления. Вы также можете реализовать MedianVisitor, MeanVisitor, MaximumVisitor и так далее. Каждый из них реализует generic IVisitor интерфейс с Visit(Element) метод.

для коллекции верно обратное: он не знает о том, что делает посетитель, и просто заботится о контроле потока, вызывая visitor.Visit(element) для каждого элемента в коллекции. Различные реализации посетителей все выглядят одинаково для коллекции.

инверсия управления и построение графа объектов

в этом случае "контроль" означает " контроль над тем, как создаются и подключаются компоненты вместе."

в любом нетривиальном приложении код разбивается на компоненты, которые должны сотрудничать. Чтобы сохранить компоненты многоразовыми, они не могут напрямую создавать друг друга, так как это будет постоянно склеивать их вместе. Вместо этого отдельные компоненты отказаться от контроля над конструкцией и компонентной проводкой.

инъекции зависимостей является одним из способов достижения этого, принимая ссылки на объекты collaborator в конструкторе. Тогда вы нужен отдельный фрагмент кода запуска, где все компоненты создаются и соединяются вместе, или структура инъекции зависимостей, которая заботится об этом для вас. Ваш класс Dice действительно является примером инъекции зависимостей.

еще один способ отказаться от контроля над построением графа объектов -Локатор Службы шаблон, хотя он имеет свой недостатки.


позвольте мне попытаться ответить.

ваш первый пример-ни то, ни другое. Это просто шаблон.

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

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

ваш второй пример выглядит как потребитель DI / IoC. Код, который отправляет реализацию Engine в ваш класс, будет компонентом DI/IoC.

надеюсь, это точно и помогает.