views:

1070

answers:

7

What is the Dependency Inversion Principle and why is it important?

+5  A: 

Check this document out: The Dependency Inversion Principle.

It basically says:

  • High level modules should not depend upon low-level modules. Both should depend upon abstractions.
  • Abstractions should never depend upon details. Details should depend upon abstractions.

As to why it is important, in short: changes are risky, and by depending on a concept instead of on an implementation, you reduce the need for change at call sites.

Effectively, the DIP reduces coupling between different pieces of code. The idea is that although there are many ways of implementing, say, a logging facility, the way you would use it should be relatively stable in time. If you can extract an interface that represents the concept of logging, this interface should be much more stable in time than its implementation, and call sites should be much less affected by changes you could make while maintaining or extending that logging mechanism.

By also making the implementation depend on an interface, you get the possibility to choose at run-time which implementation is better suited for your particular environment. Depending on the cases, this may be interesting too.

Carl Seleborg
This answer does not say why DIP is important, or even what DIP is.I have read the official DIP document, and think this is really a poor and unjustified "principle", because it's based on a flawed assumption: that high-level modules are reusable.
Rogerio
Consider a dependancy graph for some objects. Apply DIP to the objects. Now any object will be indpendent of the implementation of the other objects. Unit testing is now simple. Later refactoring for reuse is possible. Design changes have very limited change scopes. Design problems don not cascade. See also the AI pattern "Blackboard" for data dependaecy inversion. Together, very powerful tools fo making the software understandable, maintainable and reliable. Ignore dependency injection in this context. It is unrelated.
Tim Williscroft
A class A using a class B does not mean A "depends" on the implementation of B; it depends on the public interface of B only. Adding a separate abstraction on which both A and B now depend only means that A will no longer have a compile-time dependency on the public interface of B.Isolation between units can be achieved easily without these extra abstractions; there are specific mocking tools for that, in Java and .NET, that deal with all situations (static methods, constructors, etc.).Applying DIP tends to make software more complex and less maintainable, and no more testable.
Rogerio
Why is it called Dependency Inversion?
P.K
A: 

The point of dependency inversion is to make reusable software.

The idea is that instead of two pieces of code relying on each other, they rely on some abstracted interface. Then you can reuse either piece without the other.

The way this is most commonly achieved is through an Inversion of Control container like Spring in Java. In this model, properties of objects are set up through an XML configuration instead of the objects going out and finding their depenency.

Imagine this pseudocode...

public class MyClass
{
  public Service myService = ServiceLocator.service;
}

MyClass directly depends on both the Service class and the ServiceLocator class. It needs both of those if you want to use it in another application. Now imagine this...

public class MyClass
{
  public IService myService;
}

Now, MyClass relies on a single interface, the IService interface. We'd let the IoC container actually set the value of that variable.

So now, MyClass can easily be reused in other projects, without bringing the dependency of those other two classes along with it.

Even better, you don't have to drag the dependencies of MyService, and the dependencies of those dependencies, and the... well, you get the idea.

Marc Hughes
This answer really is not about DIP, but something else.Two pieces of code can rely on some abstracted interface and not in each other, and still do not follow the Dependency Inversion Principle.
Rogerio
+2  A: 

Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler is a good read too. I found Head First Design Patterns an awesome book for my first foray into learning DI and other patterns.

Chris Canal
+1  A: 

Inversion of Control is a design pattern where an Objects gets handed its dependency by an outside framework, rather than asking a framework for its dependency.

Pseudocode example using traditional lookup:

class Service {
    Database database;
    init() {
        database = FrameworkSingleton.getService("database");
    }
}

Similar code using IoC:

class Service {
    Database database;
    init(database) {
        this.database = database;
    } 
}

The benefis of IoC are:

  • You have no dependency on a central framework, so this can be changed if desired.
  • Since objects are created by injection, preferably using interfaces, it's easy to create unit tests that replace dependencies with mock versions.
  • Decoupling off code.
Staale
Is Dependency Inversion Principle and Inversion of Control the same thing?
Peter Mortensen
+1  A: 

Good answers and good examples are already given by others here.

The reason DIP is important is because it ensures the OO-principle "lousely coupled design".

The objects in your software should NOT get into a hierarchy where some objects are the top-level ones, dependent on low-level objects. Changes in low-level objects will then ripple-through to your top-level objects which makes the software very fragile for change.

You want your 'top-level' objects to be very stable and not fragile for change, therefore you need to invert the dependencies.

Hace
How exactly does DIP do that, for Java or .NET code?In those languages, contrary to C++, changes to the implementation of a low-level module do not require changes in the high-level modules that use it. Only changes in the public interface would ripple-through, but then the abstraction defined at the higher level would also have to change.
Rogerio
+12  A: 

The books Agile Software Development, Principles, Patterns, and Practices and Agile Principles, Patterns, and Practices in C# are the best resources for fully understanding the original goals and motivations behind the Dependency Inversion Principle. The article "The Dependency Inversion Principle" is also a good resource, but due to the fact that it is a condensed version of a draft which eventually made its way into the previously mentioned books, it leaves out some important discussion on the concept of a package and interface ownership which are key to distinguishing this principle from the more general advise to "program to an interface, not an implementation" found within the book Design Patterns (Gamma, et. al).

To provide a summary, the Dependency Inversion Principle is primarily about reversing the conventional direction of dependencies from "higher level" components to "lower level" components such that "lower level" components are dependent upon the interfaces owned by the "higher level" components. (Note: "higher level" component here refers to the component requiring external dependencies/services, not necessarily its conceptual position within a layered architecture.) In doing so, coupling isn't reduced so much as it is shifted from components that are theoretically less valuable for reuse to components which are theoretically more valuable for reuse.

This is achieved by designing components whose external dependencies are expressed in terms of an interface for which an implementation must be provided by the consumer of the component. In other words, the defined interfaces express what is needed by the component, not how you use the component (e.g. "INeedSomething", not "IDoSomething").

What the Dependency Inversion Principle does not refer to is the simple practice of abstracting dependencies through the use of interfaces (e.g. MyService → [ILogger ⇐ Logger]). While this decouples a component from the specific implementation detail of the dependency, it does not invert the relationship between the consumer and dependency (e.g. [MyService → IMyServiceLogger] ⇐ Logger.

A longer discussion of this principle as it relates to the simple use of interfaces, Dependency Injection, and the Separated Interface pattern can be found here.

Derek Greer
+1. Very good explanation. The best I have seen so far.
Peter Mortensen
Thanks. I see now how my answer misses the point. The difference between **MyService → [ILogger ⇐ Logger]** and **[MyService → IMyServiceLogger] ⇐ Logger** is subtle but important.
Patrick McElhaney
+2  A: 

To me, the Dependency Inversion Principle, as described in the official article, is really a misguided attempt to increase the reusability of modules that are inherently less reusable, as well as a way to workaround an issue in the C++ language.

The issue in C++ is that header files typically contain declarations of private fields and methods. Therefore, if a high-level C++ module includes the header file for a low-level module, it will depend on actual implementation details of that module. And that, obviously, is not a good thing. But this is not an issue in the more modern languages commonly used today.

High-level modules are inherently less reusable than low-level modules because the former are normally more application/context specific than the latter. For example, a component that implements an UI screen is of the highest-level and also very (completely?) specific to the application. Trying to reuse such a component in a different application is counter-productive, and can only lead to over-engineering.

So, the creation of a separate abstraction at the same level of a component A that depends on a component B (which does not depend on A) can be done only if component A will really be useful for reuse in different applications or contexts. If that's not the case, then applying DIP would be bad design.

Rogerio