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

What is the difference between Inversion of Control and Dependency injection in C++?

我最近一直在阅读C++中的DI和IOC。我有点困惑(甚至在阅读相关问题之后),希望有一些澄清。

在我看来,熟悉STL和Boost会导致相当多的依赖注入的使用。例如,假设我做了一个函数,找到了一系列数字的平均值:

1
2
3
4
5
6
7
8
9
10
11
12
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;
};

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

让我们来看另一个例子。我们有一个班:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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_;
};

这看起来像是依赖注入。但这是控制反转吗?

另外,如果我错过了什么,有人能帮我吗?这似乎是做事情的自然方式,所以如果这就是依赖注入的全部,为什么人们很难使用它?


控制反转是一个非常通用的概念,根据你所说的"控制"的类型,它有不同的含义。依赖注入是一种特殊的形式。

控制反转与迭代

在这种情况下,"控制"是指"流量控制"。

我认为涉及迭代的第一个例子并不是真正的控制反转,因为代码显式地执行流控制。控制反转将要执行的操作与流控制分离。它可能看起来像这样(请原谅我的Java/C):

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

Visitor对象为它访问的每个集合元素做一些事情,例如更新一个sum counter字段。但它无法控制集合如何或何时调用它,因此控制权倒置。您还可以实现MedianVisitorMeanVisitorMaximumVisitor等。每一个都实现一个通用的IVisitor接口和一个Visit(Element)方法。

对于集合,相反的情况是正确的:它不知道访问者做什么,只是通过为集合中的每个元素调用visitor.Visit(element),来处理流控制。对于集合,不同的访问者实现看起来都相同。

控制反转与对象图构造

在这种情况下,"控制"是指"控制如何创建和连接组件"。

在任何重要的应用程序中,代码都被分解为必须协作的组件。为了保持组件的可重用性,它们不能直接创建彼此,因为这样会永久地将它们粘在一起。相反,单个组件放弃了对结构和组件布线的控制。

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

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


让我试着回答。

第一个例子两者都不是。它只是一个模板。

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

要使其成为IOC,模板必须在运行时(而不是编译时)提供给实现类型,并用作"mean()"函数的实现(想想提供mean函数实现的工厂)。

第二个例子看起来像是DI/IOC的消费者。将引擎实现发送到类中的代码是DI/IOC组件。

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