C ++中的Inversion of Control和Dependency注入有什么区别?

时间:2010-04-15 20:00:34

标签: c++ dependency-injection inversion-of-control

我最近一直在阅读C ++中的DI和IoC。我有点困惑(即使在此处阅读相关问题之后),并希望得到一些澄清。

在我看来,熟悉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 个答案:

答案 0 :(得分:17)

Inversion of Control是一个非常通用的概念,具有不同的含义,取决于您所谈论的“控制”类型。依赖注入是一种特定的形式。

控制和迭代的反转

在这种情况下,“控制”意味着“流量控制”。

我认为你的第一个涉及迭代的例子并不是真正的控制反转,因为该代码明确地执行了流控制。控制反转将将要执行的动作与流控制分开。它可能看起来像这样(原谅我的java / C#):

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

访问者对象为其访问的每个集合元素执行某些操作,例如更新和计数器字段。但它没有控制集合调用它的方式和时间,因此控制反转。您还可以实施MedianVisitorMeanVisitorMaximumVisitor等。每个都使用IVisitor方法实现通用Visit(Element)接口。

对于集合,情况正好相反:它不了解访问者的行为,只需通过为集合中的每个元素调用visitor.Visit(element)来处理流控制。不同的访客实现对于集合看起来都是一样的。

控制反转和对象图构建

在这种情况下,“控制”意味着“控制如何创建和连接组件”。

在任何非平凡的应用程序中,代码都会分成必须协作的组件。为了使组件可重复使用,它们不能直接相互创建,因为它们会永久地将它们粘合在一起。相反,单个组件放弃对构造和组件布线的控制

Dependency injection是通过在构造函数中引用协作者对象来实现此目的的一种方法。然后,您需要一个单独的启动代码,其中所有组件都已创建并连接在一起,或者需要依赖注入框架来处理此问题。你的Dice类确实是依赖注入的一个例子。

放弃对象图构造控制的另一种方法是Service Locator模式,尽管它有disadvantages

答案 1 :(得分:1)

让我试着回答。

你的第一个例子不是。它只是一个模板。

要使其成为依赖注入,必须选择一个IMPLEMENTATION,并将其提供给模板。

要使它成为IoC,模板必须在运行时(不是编译时)提供给IMPLEMENTATION类型,并用作“mean()”函数的实现(想想提供平均函数的工厂)实现)

您的第二个示例看起来像是DI / IoC的消费者。将Engine实现发送到您的类中的代码将是DI / IoC组件。

希望这是准确的,也是有帮助的。