在我看来,熟悉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_; };
这似乎是依赖注入.但是控制倒置呢?
另外,如果我缺少某些东西,有人可以帮助我吗?这似乎是自然的做事方式,所以如果这些都是依赖注入的,为什么人们很难使用它?
解决方法
反转控制和迭代
在这种情况下,“控制”是指“流量控制”.
我认为你的第一个例子涉及迭代并不是真正的反转控制,因为该代码显式地执行流控制.控制的反转会将执行的动作与流量控制分开.它可能看起来像这样(赦免我的java / C#):
SumVisitor sumVisitor = new SumVisitor(); collection.AcceptVisitor(sumVisitor); int sum = sumVisitor.GetSum();
访问对象对其访问的每个集合元素执行某些操作,例如更新总计数字段.但是它无法控制如何或什么时候被收集,所以反转控制.您还可以实现一个MedianVisitor,MeanVisitor,MaximumVisitor等.每个都使用Visit(Element)方法实现一个通用的IVisitor接口.
对于集合,恰恰相反:它不知道访问者做什么,只需通过调用该集合中每个元素的visitor.Visit(element)来处理流控制.不同的访问者实现对于集合来说都是一样的.
反转控制和对象图构造
在这种情况下,“控制”是指“控制组件的创建和连接在一起”.
在任何非平凡的应用程序中,代码被分割成必须协作的组件.为了保持组件可重用,它们不能直接相互创建,因为它们将永久粘合在一起.相反,各个组件放弃对结构和组件接线的控制.
Dependency injection是通过引用构造函数中的协作者对象来实现的一个方法.然后,您需要一个独立的启动代码,其中所有组件都将在一起创建并连接在一起,或者依赖注入框架为您照顾.你的骰子类确实是依赖注入的一个例子.
另一种放弃对象图构造控制的方式是Service Locator模式,尽管它有disadvantages.