The difference may seem slight, but even with the ServiceLocator, the class is still responsible for creating its dependencies. It just uses the service locator to do it. With DI, the class is given its dependencies. It neither knows, nor cares where they come from. One important result of this is that the DI example is much easier to unit test -- because you can pass it mock implementations of its dependent objects. You could combine the two -- and inject the service locator (or a factory), if you wanted.
Inversion of Control is a very generic concept, with different meanings depending on the sort of "control" you're talking about. Dependency injection is a specific form.
Inversion of Control and iteration
In this case "control" means "flow control".
I think your first example involving iteration is not really inversion of control, because that code explicitly does the flow control. Inversion of control would separate the action to perform from the flow control. It might look like this (pardon my java/C#):
SumVisitor sumVisitor = new SumVisitor();
collection.AcceptVisitor(sumVisitor);
int sum = sumVisitor.GetSum();
The visitor object does something for each collection element it visits, e.g. update a sum counter field. But it has no control over how or when it is called by the collection, hence inversion of control. You could also implement a MedianVisitor
, MeanVisitor
, MaximumVisitor
, etcetera. Each one implements a generic IVisitor
interface with a Visit(Element)
method.
For the collection, the opposite is true: it has no knowledge about what the visitor does and simply takes care of the flow control by calling visitor.Visit(element)
for each element in the collection. Different visitor implementations all look the same for the collection.
Inversion of Control and object graph construction
In this case "control" means "control over how components are created and wired together".
In any non-trivial application, code is split into components which have to collaborate. To keep the components reusable, they cannot directly create each other as that would permanently glue them together. Instead, individual components give up control over construction and component wiring.
Dependency injection is one way to achieve this, by taking references to collaborator objects in the constructor. You then need a separate piece of start-up code where all the components are created and wired together, or a dependency injection framework that takes care of this for you. Your Dice class is indeed an example of dependency injection.
Another way to give up control over object graph construction is the Service Locator pattern, though it has its disadvantages.
Best Answer
Decoupling is a very general principle applicable in many fields. Dependency inversion is a specific form of decoupling where you decouple the higher levels of your system from the lower levels by separating them into libraries and using interfaces. This allows you to replace lower level parts of your system without major rework.
For example, instead of the higher level parts of the system creating concrete instances of the lower level classes, an IoC container can be used to decouple how objects are created.
Inversion of control is a design principle used by framework libraries that allow the framework to regain some control from the application. I.e., a windowing framework may call back into application code when certain user interface events occur. Martin Fowler uses the term Hollywood Principle as in Don't call us, we'll call you. Decoupling is an important part of inversion of control.
But what has an IoC container to do with inversion of control? To quote Martin Fowler:
(Note that Martin Fowler talks about dependency injection, not dependency inversion.)
An IoC container helps to implement dependency injection and perhaps a better term would be dependency injection container. However, the IoC container name seems to stick. Dependency injection is an important component in dependency inversion, but the use of IoC containers for dependency injection can be confusing as inversion of control is a broader and more generic principle.
You point out that the naming isn't very consistent but that shouldn't be a big surprise as these terms have been independently invented and used even though they overlap.