codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Follow publication

Photo by rawpixel on Unsplash

The Dependency Inversion Principle

Richard Toms
codeburst
Published in
2 min readDec 14, 2018

Introduction

The dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are reversed, thus rendering high-level modules independent of the low-level module implementation details. The principle states:

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

By dictating that both high-level and low-level objects must depend on the same abstraction this design principle inverts the way some people may think about object-oriented programming.

In real terms, instead of saying that a method requires the specific VideoPlayer class, it should require an object that adheres to the VideoPlayerInterface instead. This way we can pass many versions of Video Player into the same method and it will function in the same manner.

Practical Example(s)

Violating the DIP

Below is an example of the SendWelcomeMessage class that accepts an instance of the Mailer class in its constructor as an injected dependency. This is a violation of the Dependency Inversion Principle as the method is relying upon a concretion rather than an abstraction.

class Mailer
{
// Methods for a Mailer class
}
class SendWelcomeMessage
{
private $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
}

Abiding by the DIP

To refactor this code in a way that abides by the Dependency Inversion Principle, you would have to extract the common methods that make a Mailer class. To keep things simple, we will extract a method called send, so that every instance of the MailerInterface comtract can send something.

interface MailerInterface
{
public function send();
}
class SmtpMailer implements MailerInterface
{
public function send()
{
// Send an email via SMTP
}
}
class SendSlackMailer implements MailerInterface
{
public function send()
{
// Send a message via Slack
}
}
class SendWelcomeMessage
{
private $mailer;
public function __construct(MailerInterface $mailer)
{
$this->mailer = $mailer;
}
}

As you can see from the above, we can now create any kind of MailerInterface and it will still work exactly as we would expect because it implements the send method like our contract requires.

Conclusion

The concept of this principle is that instead of saying that your class requires a specific object, such as a Mailer class that can only send emails, that you have a MailerInterface contract that defines how a mail should be sent and then use that as a dependency.

Published in codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Written by Richard Toms

A genuine geek that loves to build stuff, software is my tool.

Responses (1)

Write a response