DEV Community

Cover image for SOLID in Software Development - 5
ajay-8192
ajay-8192

Posted on

SOLID in Software Development - 5

Dependency Inversion Principle (DIP)

The Dependency Inversion Principle (DIP) states that "High-level modules should not depend on low-level modules; both should depend on abstractions." In other words, we should depend on high-level abstractions (interfaces, abstract classes) rather than on low-level concretions (concrete classes, implementations). This makes our code more flexible and easier to test.

Here is an example of how the DIP can be violated:

public class EmailService {
    private SendEmailUseCase sendEmailUseCase;

    public EmailService(SendEmailUseCase sendEmailUseCase) {
        this.sendEmailUseCase = sendEmailUseCase;
    }

    public void sendEmail(String to, String subject, String body) {
        sendEmailUseCase.sendEmail(to, subject, body);
    }
}

public class SendEmailUseCase {
    private SMTPClient smtpClient;

    public SendEmailUseCase(SMTPClient smtpClient) {
        this.smtpClient = smtpClient;
    }

    public void sendEmail(String to, String subject, String body) {
        smtpClient.connect();
        smtpClient.send(to, subject, body);
        smtpClient.disconnect();
    }
}
Enter fullscreen mode Exit fullscreen mode

The EmailService class depends on the SendEmailUseCase class, which in turn depends on the SMTPClient class. This violates the DIP because the EmailService class depends on a low-level concretion (SMTPClient). This makes the EmailService classless flexible and more difficult to test.

A better way to design this code would be to use an interface to abstract the SMTPClient class:

public interface SMPTClient {
    void connect();
    void send(String to, String subject, String body);
    void disconnect();
}

public class EmailService {
    private SMPTClient smtpClient;

    public EmailService(SMPTClient smtpClient) {
        this.smtpClient = smtpClient;
    }

    public void sendEmail(String to, String subject, String body) {
        smtpClient.connect();
        smtpClient.send(to, subject, body);
        smtpClient.disconnect();
    }
}

public class MockSMPTClient implements SMPTClient {
    @Override
    public void connect() {
        // Implement mock connection logic
    }

    @Override
    public void send(String to, String subject, String body) {
        // Implement mock send logic
    }

    @Override
    public void disconnect() {
        // Implement mock disconnect logic
    }
}

public class SendEmailUseCase {
    private SMPTClient smtpClient;

    public SendEmailUseCase(SMPTClient smtpClient) {
        this.smtpClient = smtpClient;
    }

    public void sendEmail(String to, String subject, String body) {
        smtpClient.connect();
        smtpClient.send(to, subject, body);
        smtpClient.disconnect();
    }
}
Enter fullscreen mode Exit fullscreen mode

This code follows the DIP because the EmailService class depends on an interface (SMPTClient) rather than on a low-level concretion (SMTPClient). This makes the EmailService class more flexible and easier to test.

**** πŸ’»ALL THE BESTπŸ’» ****

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Eliminate Context Switching and Maximize Productivity

Pieces.app

Pieces Copilot is your personalized workflow assistant, working alongside your favorite apps. Ask questions about entire repositories, generate contextualized code, save and reuse useful snippets, and streamline your development process.

Learn more

πŸ‘‹ Kindness is contagious

Please leave a ❀️ or a friendly comment on this post if you found it helpful!

Okay