2010-04-15 103 views
10

我最近一直在阅读关于DI和IoC的C++。我有点困惑(即使在阅读SO的相关问题之后),并希望有所澄清。C++中的Inversion of Control和Dependency injection有什么区别?

在我看来,熟悉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_; 
}; 

这似乎是依赖注入。但它是否反转控制?

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

+1

你读过维基了吗?它有一个非常明确的定义IoC/DI http://en.wikipedia.org/wiki/Inversion_of_control – CDSO1 2010-04-15 20:09:25

+6

在C++中,我们不做IoC或DI - 我们有我们自己的自命不凡和严重命名的概念。 – 2010-04-15 20:18:04

+0

如果你不小心,你的模板函数可能会被零分。 – 2010-04-15 20:20:37

回答

14

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

逆控制的和迭代

在这种情况下“控制”是指“流控制”。

我认为你的第一个涉及迭代的例子并不是真正的控制反转,因为那个代码明确地执行了流控制。控制倒置会将要执行的操作与流量控制分开。这可能是这样的(请原谅我的Java/C#):

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

参观者对象做了它访问的每个集合元素,例如更新总计计数器字段。但它没有控制在何时或何时被集合调用,因此控制反转。您也可以实施MedianVisitorMeanVisitor,MaximumVisitor等等。每一个都使用Visit(Element)方法实现通用的IVisitor接口。

对于收集来说,情况正好相反:它不知道访问者的作用,通过为集合中的每个元素调用visitor.Visit(element)来简单地管理流量控制。不同的访问者实现对于集合而言都是相同的。控制的

反演和对象图结构

在这种情况下的“控制”是指“在如何组件创建和有线一起控制”。

在任何非平凡的应用程序中,代码被拆分成必须协作的组件。为了保持组件的可重用性,它们不能直接创建对方,因为它们会永久地将它们粘合在一起。取而代之的是,单个部件放弃控制过构造和部件布线。

Dependency injection是通过引用构造函数中的协作者对象来实现此目的的一种方法。然后,您需要一个单独的启动代码,其中创建所有组件并将它们连接在一起,或者需要一个依赖注入框架来为您提供帮助。你的Dice类实际上是一个依赖注入的例子。

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

1

让我试着回答。

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

因为它是依赖注入,所以必须选择一个IMPLEMENTATION并将其提供给模板。

对于IoC,模板必须在运行时(不是编译时)提供给IMPLEMENTATION类型,并用作“mean()”函数的实现(想象一下提供均值功能实现)

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

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