188

What is the dependency inversion principle and why is it important?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Phillip Wells
  • 6,624
  • 6
  • 38
  • 40
  • Refer [The Dependency Inversion Principle - Posted by Gabriel Schenker](http://lostechies.com/gabrielschenker/2009/01/30/the-dependency-inversion-principle/) – LCJ Feb 06 '14 at 19:33
  • 4
    Ridiculous quantity of answers on here using the "high level" and "low level" terms from Wikipedia. These terms are inaccessible and lead lots of readers to this page. If you're going to regurgitate wikipedia, please **define these terms in your answers** to give context! – 8bitjunkie May 06 '19 at 10:03

16 Answers16

145

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 to components which are theoretically more valuable.

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.

The importance of the Dependency Inversion Principle can be distilled down to a singular goal of being able to reuse software components which rely upon external dependencies for a portion of their functionality (logging, validation, etc.)

Within this general goal of reuse, we can delineate two sub-types of reuse:

  1. Using a software component within multiple applications with sub-dependency implementations (e.g. You've developed a DI container and want to provide logging, but don't want to couple your container to a specific logger such that everyone that uses your container has to also use your chosen logging library).

  2. Using software components within an evolving context (e.g. You've developed business-logic components which remain the same across multiple versions of an application where the implementation details are evolving).

With the first case of reusing components across multiple applications, such as with an infrastructure library, the goal is to provide a core infrastructure need to your consumers without coupling your consumers to sub-dependencies of your own library since taking dependencies upon such dependencies requires your consumers to require the same dependencies as well. This can be problematic when consumers of your library choose to use a different library for the same infrastructure needs (e.g. NLog vs. log4net), or if they choose to use a later version of the required library which isn't backward compatible with the version required by your library.

With the second case of reusing business-logic components (i.e. "higher-level components"), the goal is to isolate the core domain implementation of your application from the changing needs of your implementation details (i.e. changing/upgrading persistence libraries, messaging libraries, encryption strategies, etc.). Ideally, changing the implementation details of an application shouldn't break the components encapsulating the application's business logic.

Note: Some may object to describing this second case as actual reuse, reasoning that components such as business-logic components used within a single evolving application represents only a single use. The idea here, however, is that each change to the application's implementation details renders a new context and therefore a different use case, though the ultimate goals could be distinguished as isolation vs. portability.

While following the Dependency Inversion Principle in this second case can offer some benefit, it should be noted that its value as applied to modern languages such as Java and C# is much reduced, perhaps to the point of being irrelevant. As discussed earlier, the DIP involves separating implementation details into separate packages completely. In the case of an evolving application, however, simply utilizing interfaces defined in terms of the business domain will guard against needing to modify higher-level components due to changing needs of implementation detail components, even if the implementation details ultimately reside within the same package. This portion of the principle reflects aspects that were pertinent to the language in view when the principle was codified (i.e. C++) which aren't relevant to newer languages. That said, the importance of the Dependency Inversion Principle primarily lies with the development of reusable software components/libraries.

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. Additionally, a discussion of how the principle relates to dynamically-typed languages such as JavaScript can be found here.

Mark Amery
  • 110,735
  • 57
  • 354
  • 402
Derek Greer
  • 13,465
  • 5
  • 38
  • 47
  • 17
    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 Aug 31 '09 at 13:45
  • 2
    In the same line its very well explained here: http://lostechies.com/derickbailey/2011/09/22/dependency-injection-is-not-the-same-as-the-dependency-inversion-principle/ – ejaenv Dec 13 '12 at 13:37
  • 1
    How I wished people would stop using loggers as the canonical usecase for dependency injection. Especially in connection with log4net where its almost an anti pattern. That aside, kickass explanation! – Casper Leon Nielsen Jan 08 '13 at 17:58
  • 4
    @ Casper Leon Nielsen - D.I.P. has nothing to do with D.I. They are not synonyms nor equivalent concepts. – TSmith Apr 02 '13 at 15:59
  • This is probably the clearest explanation of DIP I've seen. That said, why is it so glorified? As I see it, what we're trying to do is minimize work re-done by changes by making the coupling occur "in the most convenient place possible." If I need to make big changes to `Logger` (say I'm no longer allowed to use a local file system), I still won't be able to adhere to `IMyServiceLogger`. It seems like we'd have to make the same amount of changes, everywhere, whether the architecture is `MyService → [ILogger ⇐ Logger]` or `[MyService → IMyServiceLogger] ⇐ Logger`. – VF1 Jul 21 '16 at 16:00
  • And in cases where the new `Logger` impl can conform to the old interface, how does this save us anything over the old approach? – VF1 Jul 21 '16 at 16:01
  • 4
    @VF1 As stated in the summary paragraph, the importance of the Dependency Inversion Principle is primarily with reuse. If John releases a library that has an external dependency on a logging library and Sam wishes to use John's library, Sam takes on the transient logging dependency. Sam will never be able to deploy his application without the logging library John selected. If John follows the DIP, however, Sam is free to provide an adapter and use whatever logging library he chooses. The DIP isn't about convenience, but coupling. – Derek Greer Nov 23 '16 at 17:39
  • @VF1 Regarding your scenario of needing to change your logging implementation, if your logging requirements necessitates you making changes throughout your system then you haven't defined your abstraction correctly whether you're following the DIP or not. A logging interface that needs to be changed if you decide not to log to the file system is an interface that is semantically coupled to the implementation details. – Derek Greer Nov 23 '16 at 17:49
  • @DerekGreer I think I understand. Sam's adapter could still be written for an `ILogger`, but I think the point to drive home is that the _easiest_ interface (in the sense that it's the most minimal) such that it satisfies the requirements necessary to make `MyService` operate. – VF1 Nov 23 '16 at 18:07
  • @VF1 That's correct. Components can be either physically coupled (makes a reference to a specific library/assembly), or they can be semantically coupled (nominal interface over a specific implementation). The DIP already presumes the implementation is going to be defined in terms of the interface rather than an interface being defined in terms of the implementation. – Derek Greer Nov 25 '16 at 17:47
  • Inherit to be used instead of using base class, the essence can be summarized as so – FaceBro Mar 10 '17 at 14:26
  • 1
    @DerekGreer: Your example with John and Sam should be in your original reply. Great one! – Birb Mar 22 '17 at 08:28
  • If we define the high level components only in terms of reusability, then we cannot understand what DIP is or what its benefits are. High level components are the ones that include the business rules, it does not have much to do with reusability indeed. Everything else should depend on the business rules, not the other way around. You can see that Uncle Bob defines high level components like this while explaining DIP in his Clean Architecture book. – humbaba Sep 06 '18 at 09:40
  • I’m curious what you believe the primary benefits to be if not reuse. I certainly don’t deny that Uncle Bob sees higher level components as those containing business logic, but pointing that out doesn’t say anything about why this would be a useful practice. – Derek Greer Sep 07 '18 at 12:22
  • @humbaba I had occasion to read back over this exchange and went back to the book "Agile Principles, ... in C#" wherein it states on pg. 154: "Moreover, it is high-level, policy-setting modules that we want to be able to reuse." So, Martin most definitely has reuse in mind when discussing the DIP. Understand too, reuse doesn't necessarily necessitate multiple uses. When an application's core exists alongside one set of implementation detail components, you can consider that to be one use. When you need to change the impl. details for the same application, that is essentially a second use. – Derek Greer Feb 15 '19 at 22:08
  • 1
    I updated the article to include discussion about goals of isolation verses merely library portability. – Derek Greer Feb 16 '19 at 00:08
  • @derekgreer The article is amazing, I love it. Thank you! But I have one question though. In the article you mentioned "Additionally, the association of the interface with the higher-level component(s) may in some cases impact the style and naming conventions used in the creation of the interface." What is this impact, and does it matter? – Wael Alshabani May 31 '19 at 00:04
  • That article could use a little touch-up. I wrote it about 10 years ago and I believe I'd probably do a better job writing it today. That aside, the take-away is that following the DIP shifts ownership of the interface from the concrete implementation to the consumer which naturally leads to differences in how the interface is expressed (i.e. the behavior the consumer needs vs. the behavior the concrete implementation generically offers). Each application tends to have its own Domain-Specific Language, so the interfaces defined will tend to reflect this. – Derek Greer May 31 '19 at 15:12
  • I updated the answer to include a link to another article I wrote in 2012 about how the principle applies in dynamically-typed languages like JavaScript. – Derek Greer May 31 '19 at 15:17
  • What's the meaning of the syntax with arrows and square brackets (`→`, `⇐`, `[`, `]`) that you use in this answer? They're left undefined here, but are alien to me. – Mark Amery Jun 10 '19 at 10:36
  • With the arrows, I was trying to approximate the UML class diagram functions of association and generalization with → and ⇐ respectively. The brackets are indicative that the classes involved are in the same "package" (e.g. in the same assembly in .Net). Understanding the notion of package is a key distinguishing concept when talking about DIP. Otherwise you just end up with the general advice of "Program to an Interface not an Implementation". – Derek Greer Jun 19 '19 at 15:21
  • 1) I have read that the brackets supposedly express that the classes between them are in the same (e.g. Java?) package, but I'm unable to see the difference in practice between MyService → [ILogger ⇐ Logger] and [MyService → IMyServiceLogger] ⇐ Logger. Assuming that ILogger and IMyServiceLogger are classes I created in my application to abstract the implementation details of the logging library I'm using, what's the difference of putting them in different packages? 2) Where is the dependency inversion if MyService depends on an interface and Logger implements that interface in both cases? – Alan Evangelista Nov 11 '20 at 10:30
111

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.

Nick Weaver
  • 46,888
  • 12
  • 96
  • 106
Carl Seleborg
  • 12,771
  • 11
  • 51
  • 70
  • 31
    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. – Rogério Aug 30 '09 at 21:42
  • 3
    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 Aug 30 '09 at 22:50
  • 6
    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. – Rogério Aug 31 '09 at 17:33
  • Why is it called Dependency Inversion? – P.K Aug 31 '09 at 18:48
  • 1
    Then what is inversion of control? a way to achieve Dependency Inversion? – user20358 Sep 26 '12 at 20:47
  • 2
    @Rogerio, see Derek Greer response below, he explains it. AFAIK, DIP says that it's A who mandates what A needs, and not B who says what A needs. So, the interface that A needs should not be given by B, but for A. – ejaenv Dec 13 '12 at 13:53
  • 1
    +1 for `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.` – darxtrix Apr 23 '17 at 10:12
  • 1
    Please expand your answer to define a high level and a low level module. – 8bitjunkie May 06 '19 at 10:04
  • 1
    An example would have been appreciated. – Juzer Ali Aug 12 '19 at 11:55
  • @TimWilliscroft, Dependency Inversion Principle and Dependency Injection are indeed related, [as put by Mark Seeman](https://stackoverflow.com/a/6767514/3002584): "DIP [Dependency Inversion Principle] is the principle that guides us towards DI [Dependency Injection]". – OfirD Jan 03 '21 at 22:16
  • @OfirD Dependency injection (DI) is a technique to satisfy dependencies, the Dependancy inversion is a design principle. DI is an attempt to make DIP happen by adding a dependency to your DI framework. Perhaps adding more code does not make a software system better. DI tends to be somewhat magical in operation, where DIP is a very simple thing. – Tim Williscroft Apr 18 '21 at 23:48
15

When we design software applications we can consider the low level classes the classes which implement basic and primary operations (disk access, network protocols,...) and high level classes the classes which encapsulate complex logic (business flows, ...).

The last ones rely on the low level classes. A natural way of implementing such structures would be to write low level classes and once we have them to write the complex high level classes. Since high level classes are defined in terms of others this seems the logical way to do it. But this is not a flexible design. What happens if we need to replace a low level class?

The Dependency Inversion Principle states that:

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

This principle seeks to "invert" the conventional notion that high level modules in software should depend upon the lower level modules. Here high level modules own the abstraction (for example, deciding the methods of the interface) which are implemented by lower level modules. Thus making lower level modules dependent on higher level modules.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
nikhil.singhal
  • 168
  • 1
  • 6
11

Dependency inversion well applied gives flexibility and stability at the level of the entire architecture of your application. It will allow your application to evolve more securely and stable.

Traditional layered architecture

Traditionally a layered architecture UI depended on the business layer and this in turn depended on the data access layer.

You have to understand layer, package, or library. Let's see how the code would be.

We would have a library or package for the data access layer.

// DataAccessLayer.dll
public class ProductDAO {

}

And another library or package layer business logic that depends on the data access layer.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private ProductDAO productDAO;
}

Layered architecture with dependency inversion

The dependency inversion indicates the following:

High-level modules should not depend on low-level modules. Both should depend on abstractions.

Abstractions should not depend on details. Details should depend on abstractions.

What are the high-level modules and low level? Thinking modules such as libraries or packages, high-level module would be those that traditionally have dependencies and low level on which they depend.

In other words, module high level would be where the action is invoked and low level where the action is performed.

A reasonable conclusion to draw from this principle is that there should be no dependence between concretions, but there must be a dependence on an abstraction. But according to the approach we take we can be misapplying investment depend dependency, but an abstraction.

Imagine that we adapt our code as follows:

We would have a library or package for the data access layer which define the abstraction.

// DataAccessLayer.dll
public interface IProductDAO
public class ProductDAO : IProductDAO{

}

And another library or package layer business logic that depends on the data access layer.

// BusinessLogicLayer.dll
using DataAccessLayer;
public class ProductBO { 
    private IProductDAO productDAO;
}

Although we are depending on an abstraction dependency between business and data access remains the same.

To get dependency inversion, the persistence interface must be defined in the module or package where this high level logic or domain is and not in the low-level module.

First define what the domain layer is and the abstraction of its communication is defined persistence.

// Domain.dll
public interface IProductRepository;

using DataAccessLayer;
public class ProductBO { 
    private IProductRepository productRepository;
}

After the persistence layer depends on the domain, getting to invert now if a dependency is defined.

// Persistence.dll
public class ProductDAO : IProductRepository{

}


(source: xurxodev.com)

Deepening the principle

It is important to assimilate the concept well, deepening the purpose and benefits. If we stay in mechanically and learn the typical case repository, we will not be able to identify where we can apply the principle of dependence.

But why do we invert a dependency? What is the main objective beyond specific examples?

Such commonly allows the most stable things, that are not dependent on less stable things, to change more frequently.

It is easier for the persistence type to be changed, either the database or technology to access the same database than the domain logic or actions designed to communicate with persistence. Because of this, the dependence is reversed because as it is easier to change the persistence if this change occurs. In this way we will not have to change the domain. The domain layer is the most stable of all, which is why it should not depend on anything.

But there is not just this repository example. There are many scenarios where this principle applies and there are architectures based on this principle.

Architectures

There are architectures where dependency inversion is key to its definition. In all the domains it is the most important and it is abstractions that will indicate the communication protocol between the domain and the rest of the packages or libraries are defined.

Clean Architecture

In Clean architecture the domain is located in the center and if you look in the direction of the arrows indicating dependency, it is clear what are the most important and stable layers. The outer layers are considered unstable tools so avoid depending on them.


(source: 8thlight.com)

Hexagonal Architecture

It happens the same way with the hexagonal architecture, where the domain is also located in the central part and ports are abstractions of communication from the domino outward. Here again it is evident that the domain is the most stable and traditional dependence is inverted.

Glorfindel
  • 19,729
  • 13
  • 67
  • 91
xurxodev
  • 1,281
  • 18
  • 15
  • I'm not sure what it's meant to say, but this sentence is incoherent: *"But according to the approach we take we can be misapplying investment depend dependency, but an abstraction."* Perhaps you'd like to fix? – Mark Amery Jan 18 '20 at 16:41
10

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.

Rogério
  • 15,243
  • 2
  • 44
  • 62
  • Even if the high-level abstraction is useful only in context of that application it can have value when you want to replace the real implementation with a stub for testing (or provide command-line interface to an application usually available on the web) – Przemek Pokrywka Mar 22 '13 at 19:40
  • 3
    DIP is important across languages and has nothing to do with C++ itself. Even if your high level code will never leave your application, DIP allows you to contain code change when you add or change lower level code. This reduces both maintenance costs and the unintended consequences of change. DIP is a higher level concept. If you do not understand it you need to do more googling. – Dirk Bester Aug 25 '13 at 20:09
  • 3
    I think you misunderstood what I said about C++. It was just a *motivation* for DIP; no doubt it's more general than that. Note the official article about DIP makes it clear the central motivation was to support reuse of high-level modules, by making them immune to changes in low-level modules; with no need for reuse, then it's very likely to be overkill and over-engineering. (Did you read it? It also talks about the C++ issue.) – Rogério Aug 26 '13 at 13:46
  • 1
    Aren't you overlooking the reverse application of DIP? That is, the higher level modules implement your application, essentially. Your primary concern isn't to reuse it, it's to make it less dependent on the implementations of lower-level modules so that updating it to keep pace with future changes isolates your application from the ravages of time and new technology. It's not to make it easier to replace WindowsOS, it's to make WindowsOS less dependent on the FAT/HDD's implementation details so that the newer NTFS/SSD's can be plugged into WindowsOS with no or little impact. – knockNrod Apr 21 '16 at 13:38
  • @knockNrod I see what you're saying, but that is not DIP. With DIP, the interface which is implemented by lower-level components is defined at the *same* level as the high-level (and application specific) components which use the interface. In the situation you described, this interface would be defined at an intermediate level, with the high-level components having a non-inverted dependency on it. A concrete example would be a business app using the JPA interface, which gets implemented by Hibernate; between these three levels, there would be no dependency inversion. – Rogério Apr 21 '16 at 18:52
  • In my previous comment, I forgot that the JPA library actually *does* apply DIP with respect to implementation libraries like Hibernate and EclipseLink, since JPA (which is at the higher level) defines the interfaces that get implemented by those concrete ORM libraries (which are at a lower level) - so here the dependency between JPA and Hibernate is inverted. This doesn't change my overall point, though, as JPA is a fully reusable library, and any application depending on it would have said dependencies on the "normal" direction, not inverted. – Rogério Apr 21 '16 at 19:09
  • 1
    UI screen is definitely not the highest level module or should not be for any application. Highest level modules are the ones that contain business rules. A highest level module is not defined by its potential for reusability as well. Please check Uncle Bob's simple explanation in this article: http://blog.cleancoder.com/uncle-bob/2016/01/04/ALittleArchitecture.html – humbaba Sep 06 '18 at 09:33
  • Link is broken. Might want to dig up a version from the Wayback Machine. – Mark Amery Jan 18 '20 at 15:57
  • -1 because this answer never actually defines the Dependency Inversion Principle before launching into its opinionated commentary about it. Having the commentary is fine, but you should answer the objective question about what the principle is, first. – Mark Amery Jan 18 '20 at 15:58
8

Basically it says:

Class should depend on abstractions (e.g interface, abstract classes), not specific details (implementations).

martin.ra
  • 113
  • 1
  • 2
  • Can it be that simple? There are long articles and even books as DerekGreer mentioned? I actually was looking for simple answer, but its unbelievable if it is that simple :D – Dariux Jan 10 '18 at 20:19
  • 1
    @darius-v it is not another version of saying "use abstractions". It is about who owns the interfaces. The principal says client (higher level components) should define interfaces and lower level components should implement them. – boran Jan 13 '18 at 16:12
6

A much clearer way to state the Dependency Inversion Principle is:

Your modules which encapsulate complex business logic should not depend directly on other modules which encapsulate business logic. Instead, they should depend only on interfaces to simple data.

I.e., instead of implementing your class Logic as people usually do:

class Dependency { ... }
class Logic {
    private Dependency dep;
    int doSomething() {
        // Business logic using dep here
    }
}

you should do something like:

class Dependency { ... }
interface Data { ... }
class DataFromDependency implements Data {
    private Dependency dep;
    ...
}
class Logic {
    int doSomething(Data data) {
        // compute something with data
    }
}

Data and DataFromDependency should live in the same module as Logic, not with Dependency.

Why do this?

  1. The two business logic modules are now decoupled. When Dependency changes, you don't need to change Logic.
  2. Understanding what Logic does is a much simpler task: it operates only on what looks like an ADT.
  3. Logic can now be more easily tested. You can now directly instantiate Data with fake data and pass it in. No need for mocks or complex test scaffolding.
mattvonb
  • 183
  • 1
  • 5
  • 1
    I don't think this is right. If `DataFromDependency`, which directly references `Dependency`, is in the same module as `Logic`, then the `Logic` module still directly depends on `Dependency` module at compile time. Per [Uncle Bob's explanation of the principle](http://blog.cleancoder.com/uncle-bob/2016/01/04/ALittleArchitecture.html), avoiding that is the whole point of DIP. Rather, to follow DIP, `Data` should be in same module as `Logic`, but `DataFromDependency` should be in the same module as `Dependency`. – Mark Amery Jan 18 '20 at 16:52
  • Maybe `DataFromDependency` and `Data` should indeed be defined in a module separate from `Logic`, but they definitely should not go in the same module as `Dependency`. That is often impossible, e.g., when `Dependency` is from an external library.) – mattvonb Feb 19 '21 at 23:16
6

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

The reason DIP is important is because it ensures the OO-principle "loosely 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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Hace
  • 1,362
  • 11
  • 16
  • 6
    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. – Rogério Aug 30 '09 at 22:01
3

Inversion of control (IoC) is a design pattern where an object 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 benefits 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.
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Staale
  • 24,584
  • 22
  • 63
  • 85
  • 1
    Is Dependency Inversion Principle and Inversion of Control the same thing? – Peter Mortensen Aug 04 '09 at 23:18
  • 3
    The "inversion" in DIP is *not* the same as in Inversion of Control. The first one is about compile-time dependencies, while the second one is about the flow of control between methods at runtime. – Rogério Nov 08 '10 at 15:38
  • I feel like the IoC version is missing something. How is what Database object it gets defined, where does it come from. I'm trying to understand how this doesn't just delay specifying all the dependancies to the top level in a giant god dependancy – Richard Tingle Jun 22 '15 at 14:13
  • 1
    As already said by @Rogério, DIP is not DI/IoC. This answer is wrong IMO – zeraDev Mar 25 '19 at 15:25
  • @RichardTingle giant list of dependencies plural. i don't see anything wrong with that. it's more clear and upfront summarized for you as you read the code too, rather than having to dig all throughout the code in convoluted paths to discover an independent variable. – ahnbizcad Nov 06 '20 at 22:20
1

If we can take it as a given that a "high level" employee at a corporation is paid for the execution of their plans, and that these plans are delivered by the aggregate execution of many "low level" employee's plans, then we could say it is generally a terrible plan if the high level employee's plan description in any way is coupled to the specific plan of any lower level employee.

If a high level executive has a plan to "improve delivery time", and indicates that an employee in the shipping line must have coffee and do stretches each morning, then that plan is highly coupled and has low cohesion. But if the plan makes no mention of any specific employee, and in fact simply requires "an entity that can perform work is prepared to work", then the plan is loosely coupled and more cohesive: the plans do not overlap and can easily be substituted. Contractors, or robots, can easily replace the employees and the high level's plan remains unchanged.

"High level" in the dependency inversion principle means "more important".

mike
  • 224
  • 1
  • 4
  • 14
  • 1
    This is a remarkably good analogy. Much as, under the DIC, high-level components still depend *at runtime* on low-level ones, in this analogy, the execution of the high-level plans depends on the low-level plans. But also, just as under DIC it's the low-level plans that depend *at compile time* on the high-level plans, it's the case in your analogy that the formation of the low-level plans depends on the high-level plans. – Mark Amery Jan 18 '20 at 17:44
1

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 (IoC) 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 dependency.

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Marc Hughes
  • 5,688
  • 2
  • 33
  • 46
  • 3
    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. – Rogério Aug 30 '09 at 22:11
  • your example should explicitly contain the variation of myService being passed into it (e.g. constructor param) in order to make the example complete. You don't just declare an interface and now you can use it. – ahnbizcad Nov 06 '20 at 22:22
1

Dependency Inversion Principle(DIP)

It is a part of SOLID[About] which is a part of OOD and was introduced by Uncle Bob. It is about loose coupling between classes(layers...). Class should not be depended on concrete realization, class should be depended on abstraction/interface

Problem:

//A -> B
class A {
  B b

  func foo() {
     b = B();
  }
}

Solution:

//A -> IB <|- B
//client[A -> IB] <|- B is the Inversion 
class A {
  B ib

  func foo() {
     ib = B()
  }
}

Now A is not depended on B(one to one), now A is depended on interface IB which is implemented by B, it means that A depends on multiple realization of IB(one to many)

[DIP vs DI vs IoC]

yoAlex5
  • 13,571
  • 5
  • 105
  • 98
-1

Dependency inversion: Depend on abstractions, not on concretions.

Inversion of control: Main vs Abstraction, and how the Main is the glue of the systems.

DIP and IoC

These are some good posts talking about this:

https://coderstower.com/2019/03/26/dependency-inversion-why-you-shouldnt-avoid-it/

https://coderstower.com/2019/04/02/main-and-abstraction-the-decoupled-peers/

https://coderstower.com/2019/04/09/inversion-of-control-putting-all-together/

-1

I can see good explanation has been given in above answers. However i wants to provide some easy explanation with simple example.

Dependency Inversion Principle allows the programmer to remove the hardcoded dependencies so that the application becomes loosely coupled and extendable.

How to achieve this : through abstraction

Without dependency inversion:

 class Student {
    private Address address;

    public Student() {
        this.address = new Address();
    }
}
class Address{
    private String perminentAddress;
    private String currentAdrress;

    public Address() {
    }
} 

In above code snippet, address object is hard-coded. Instead if we can use dependency inversion and inject the address object by passing through constructor or setter method. Let's see.

With dependency inversion:

class Student{
    private Address address;

    public Student(Address address) {
        this.address = address;
    }
    //or
    public void setAddress(Address address) {
        this.address = address;
    }
}
Sumanth Varada
  • 872
  • 10
  • 15
-2

Dependency Inversion Principle (DIP) says that

i) High level modules should not depend upon low-level modules. Both should depend upon abstractions.

ii) Abstractions should never depend upon details. Details should depend upon abstractions.

Example:

    public interface ICustomer
    {
        string GetCustomerNameById(int id);
    }

    public class Customer : ICustomer
    {
        //ctor
        public Customer(){}

        public string GetCustomerNameById(int id)
        {
            return "Dummy Customer Name";
        }
    }

    public class CustomerFactory
    {
        public static ICustomer GetCustomerData()
        {
            return new Customer();
        }
    }

    public class CustomerBLL
    {
        ICustomer _customer;
        public CustomerBLL()
        {
            _customer = CustomerFactory.GetCustomerData();
        }

        public string GetCustomerNameById(int id)
        {
            return _customer.GetCustomerNameById(id);
        }
    }

    public class Program
    {
        static void Main()
        {
            CustomerBLL customerBLL = new CustomerBLL();
            int customerId = 25;
            string customerName = customerBLL.GetCustomerNameById(customerId);


            Console.WriteLine(customerName);
            Console.ReadKey();
        }
    }

Note: Class should depend on abstractions like interface or abstract classes, not specific details (implementation of interface).

Rejwanul Reja
  • 934
  • 1
  • 14
  • 16
-2

Adding to the flurry of generally good answers, I'd like to add a tiny sample of my own to demonstrate good vs. bad practice. And yes, I'm not one to throw stones!

Say, you want a little program to convert a string into base64 format via console I/O. Here's the naive approach:

class Program
{
    static void Main(string[] args)
    {
        /*
         * BadEncoder: High-level class *contains* low-level I/O functionality.
         * Hence, you'll have to fiddle with BadEncoder whenever you want to change
         * the I/O mode or details. Not good. A good encoder should be I/O-agnostic --
         * problems with I/O shouldn't break the encoder!
         */
        BadEncoder.Run();            
    }
}

public static class BadEncoder
{
    public static void Run()
    {
        Console.WriteLine(Convert.ToBase64String(Encoding.UTF8.GetBytes(Console.ReadLine())));
    }
}    

The DIP basically says that high-level components shouldn't be dependent on low-level implementation, where "level" is the distance from I/O according to Robert C. Martin ("Clean Architecture"). But how do you get out of this predicament? Simply by making the central Encoder dependent only on interfaces without bothering how those are implemented:

class Program
{
    static void Main(string[] args)
    {           
        /* Demo of the Dependency Inversion Principle (= "High-level functionality
         * should not depend upon low-level implementations"): 
         * You can easily implement new I/O methods like
         * ConsoleReader, ConsoleWriter without ever touching the high-level
         * Encoder class!!!
         */            
        GoodEncoder.Run(new ConsoleReader(), new ConsoleWriter());        }
}

public static class GoodEncoder
{
    public static void Run(IReadable input, IWriteable output)
    {
        output.WriteOutput(Convert.ToBase64String(Encoding.ASCII.GetBytes(input.ReadInput())));
    }
}

public interface IReadable
{
    string ReadInput();
}

public interface IWriteable
{
    void WriteOutput(string txt);
}

public class ConsoleReader : IReadable
{
    public string ReadInput()
    {
        return Console.ReadLine();
    }
}

public class ConsoleWriter : IWriteable
{
    public void WriteOutput(string txt)
    {
        Console.WriteLine(txt);
    }
}

Note that you don't need to touch GoodEncoder in order to change the I/O mode — that class is happy with the I/O interfaces it knows; any low-level implementation of IReadable and IWriteable won't ever bother it.

Mark Amery
  • 110,735
  • 57
  • 354
  • 402
John Silence
  • 388
  • 4
  • 8
  • I don't think this is Dependency Inversion. After all, you haven't *inverted* any dependency here; your reader and writer don't depend on `GoodEncoder` in your second example. To create a DIP example, you need to introduce a notion of what "owns" the interfaces you've extracted here - and, in particular, to put them in the same package as the GoodEncoder while their implementations remain outside. – Mark Amery Jan 18 '20 at 17:36