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

rlb*_*ond 13 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;
};
Run Code Online (Sandbox Code Playgroud)

这是(即使用迭代器而不是访问集合本身)依赖注入?控制倒置?都不是?

让我们看另一个例子.我们有一节课:

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_;
};
Run Code Online (Sandbox Code Playgroud)

这似乎是依赖注入.但是控制倒置了吗?

另外,如果我遗失了某些东西,有人可以帮助我吗?这似乎是做事的自然方式,所以如果这就是依赖注入,为什么人们很难使用它呢?

Wim*_*nen 17

控制反转是一个非常通用的概念,具有不同的含义,取决于您所谈论的"控制"类型.依赖注入是一种特定的形式.

控制和迭代的反转

在这种情况下,"控制"意味着"流量控制".

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

SumVisitor sumVisitor = new SumVisitor();
collection.AcceptVisitor(sumVisitor);
int sum = sumVisitor.GetSum();
Run Code Online (Sandbox Code Playgroud)

访问者对象为其访问的每个集合元素执行某些操作,例如更新和计数器字段.但它无法控制集合如何或何时调用它,因此控制反转.你也可以实现MedianVisitor,MeanVisitor,MaximumVisitor,等等.每个都IVisitor使用Visit(Element)方法实现通用接口 .

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

控制反演和对象图构造

在这种情况下,"控制"意味着"控制组件如何创建和连接在一起".

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

依赖注入是实现此目的的一种方法,方法是在构造函数中引用协作者对象.那么你需要的启动代码的单独部件,所有的部件创建并连接在一起,或依赖注入框架,需要照顾这对你.你的Dice类确实是依赖注入的一个例子.

放弃对象图构造控制的另一种方法是服务定位器模式,尽管它有其缺点.