16

I'm trying to understand how the Dependency Inversion Principle differs from the "program to an interface, not an implementation" principle.

I understand what "Program to an interface, not an implementation" means. I also understand how it allows for more flexible and maintainable designs.

But I don't understand how the Dependency Inversion Principle is different from the "Program to an interface, not an implementation" principle.

I read about DIP in several places on the web, and it didn't clear up my confusion. I still don't see how the two principles differ from each other. Thanks for your help.

4 Answers 4

30

"Program to an interface" means don't depend on a concrete type to do your work, but it doesn't specify how you should get your dependency.

The "Dependency Inversion Principle" says that an object shouldn't control the creation of its dependencies, it should just advertise what dependency it needs and let the caller provide it. But it doesn't specify whether the dependency should be a concrete type or an interface.

I'll illustrate the differences with some C# code.

The following example depends on a concrete type, and it controls it's own dependency's creation. It follows neither "program to an interface" nor "dependency inversion":

public class ThingProcessor
{
    MyThing _myThing;

    public ThingProcessor()
    {
        _myThing = new MyThing();
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

The following example depends on an interface, but it controls it's own dependency's creation. It follows "program to an interface", but not "dependency inversion":

public class ThingProcessor
{
    IMyThing _myThing;

    public ThingProcessor()
    {
        _myThing = ThingFactory.GiveMeANewMyThing();
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

The following example depends on a concrete type, but it asks for its dependency to be created and passed to it. It follows "dependency inversion", but not "program to an interface":

public class ThingProcessor
{
    MyThing _myThing;

    public ThingProcessor(MyThing myThing)
    {
        _myThing = myThing;
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}

The following example depends on an interface, and it asks for its dependency to be created and passed to it. It follows both "dependency inversion" and "program to an interface":

public class ThingProcessor
{
    IMyThing _myThing;

    public ThingProcessor(IMyThing myThing) // using an interface
    {
        _myThing = myThing;
    }

    public void DoSomething()
    {
        _myThing.DoIt();
    }
}
10
  • 2
    Excellent illustration of the difference. Apr 4, 2014 at 8:24
  • 13
    What you are talking about is depenendy injection. And dependency inversion and dependency injection are two different things.
    – Euphoric
    Apr 4, 2014 at 13:14
  • 1
    @Euphoric I'm talking about the Dependency Inversion Principle, which is an abstract concept, by using Dependency Injection as the concrete implementation example. I understand the difference.
    – Eric King
    Apr 4, 2014 at 14:41
  • 1
    @EricKing Then you should explicitly say that in your answer instead of going "The "Dependency Inversion Principle" says ..." which is obviously wrong if you read my answer.
    – Euphoric
    Apr 4, 2014 at 15:21
  • 1
    I agree with Euphoric. The Dependency Inversion Principle says that higher-level layers of code should depend on lower-level pieces of code, not vice-versa. E.g. PrintStream should depend on the interface established by ByteOutputStream. Dependency Injection mentions nothing about who should depend on who.
    – Doval
    Apr 4, 2014 at 17:09
10

They are generally same thing. If you read What is the Dependency Inversion Principle and why is it important? and Dependency Inversion Principle, you will realize the two "principles" talk basically about the same thing.

  • 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.

Interface is an abstraction and implementation is a detail. If you substitute them in previous two statements, you get basically "code should depend on interfaces and not implementations". And that sounds as same thing to me.

1
  • 1
    This should be the accepted answer, the other most voted answer is misleading Jul 20, 2019 at 14:32
2

Interfaces are one way to implement DI. If you specify an interface as a parameter in the constructor method of a class, you can hand any object you like to that constructor method, so long as that object implements the interface of the constructor parameter.

In other words, programming an interface allows you to change the implementation of that interface. It's how we are able to substitute mock objects for real objects during unit testing, specify different data providers, and so forth.

0

What is the Dependency Inversion Principle exactly?

Dependency Inversion Principle (DIP for short), is a guideline that you can use to design a software system. It doesn't tell you HOW to do it exactly. There might be MANY WAYS of actually following the DIP-principle. I'll show you some examples below.

This principle isn't about any implementation details. Instead it is more about defining abstractions upfront and make your high-level classes and low-level classes depend on them. That is where the "inversion" in this principle comes from.

Instead of thinking about your design from the perspective of high-level classes, that are build out of low-level classes. Try to define abstractions upfront and make your high-level classes and low-level classes dependend on the abstractions you defined.

The definition

The DIP-principle is a requirement of your software design: high-level modules should not depend on low-level modules, both should depend on an abstraction. How you want to actually achieve this is up to you!

So what are ways to follow the DIP you might ask?

"Program to an interface, not concrete implementations" is also a guideline, but is more specific: use interfaces or abstract classes that your code should depend on. How you use those abstractions is still up to you. This is one of the ways to achieve the DIP.

interface ProductInterface 
{
    public function getPrice();
}

class Customer 
{

    private array $products;

    public function addProduct(ProductInterface $product)
    {
        array_push($this->products, $product);
    }

    public function checkout()
    {
        $total = 0;
        
        foreach ($this->products as $product)
        {
            $total += $product->getPrice();    
        }
        
        // some checkout logic that uses the price of the products.
    }
}

Dependency Injection (DI for short) is another way to do it. Here you typically get the module (dependency) injected through a constructor that has a reference to an abstraction of the dependency as the parameter type.

interface CheckoutModuleInterface
{

}

class customer
{
    public CheckoutModuleInterface $checkoutModule;
    
    // some methods to add Products are omitted. 

    public function __construct(CheckoutModuleInterface $checkoutModule)
    {
        $this->checkoutModule = $checkoutModule;
    }

    public function checkout()
    {
        $this->checkoutModule->checkout($this->products);
    }
}

In conclusion:

The difference between the two is that Dependency Inversion Principle is a higher level design principle that guides you to create modules that are loosely-coupled (don't depend on each other, but depend on abstractions). It's a way of thinking about software design, not really how you should implement it. While Program to an interface, not concrete implementations or Dependency Injection are examples of how to achieve the dependency inversion principle. And are implementation details.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.