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

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

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

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_;
};

Это походит на внедрение зависимости. Но это - инверсия управления?

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

13
задан rlbond 15 April 2010 в 20:38
поделиться

2 ответа

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

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

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

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

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

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

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

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

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

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

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

Еще один способ отказаться от контроля над построением графа объектов - это шаблон Service Locator , хотя он имеет недостатки .

17
ответ дан 1 December 2019 в 23:31
поделиться

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

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

Чтобы это была инъекция зависимости, должна быть выбрана РЕАЛИЗАЦИЯ и предоставлена ​​в шаблон.

Чтобы это был IoC, шаблон должен быть предоставлен во время выполнения (не во время компиляции) типу РЕАЛИЗАЦИЯ и использоваться как реализация функции «mean ()» (подумайте о фабрике, которая предоставляет функцию среднего реализации)

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

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

1
ответ дан 1 December 2019 в 23:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: