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();
}
}
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();
}
}
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.
Top comments (0)