SOLID Principles: Dependency Inversion Principle (DIP)
- 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.
- components should depend on abstraction.
module need to manage high-level functionality with zero implementation details this allows the module to be used for any type of application and for all modules inside the application.
- Example:
we have an existing system which sends notifications to users by email
public class Email{public void sendMail(){// send mail
}
}public class Notification{private Email _email;public Notification(){_email = new Email();
}public void promotionalNotification(){_email.sendMail();
}
}
And if we need to send a notification by SMS, we need to change email to SMS in this class, which violates DIP, because the parent class doesn’t depend on abstraction, it has a specific data tie to it.
we can solve it by:
1. create an interface.
public interface Messeneger{void sendMessage();
}
2. create classes implements this interface.
public class Email implements Messenger{void sendMessage(){// send email
}
}public class SMS implements Messenaer{void sendMessage(){// send SMS
}
}
3. build class Notification which has Messenger property.
public class Notification{private Messenger _messenger;public Notification(){_messenger = new Email();
}public void promotionalNotification(){_messeager.sendMessage();
}
}
You can replace crate a new object in three ways:
1. Constructor injection:
passing data to Notification Constructor
public class Notification{private Messenger _messenger;public Notification(Messenger messenger){_messenger= messenger;
}public void promotionalNotification(){_messenger.sendMessage();
}
}
2. Property injection:
use the setter to set a Property of Notification class
public class Notification{private Messenger messenger;public void setMessenger(Messenger messenger) {
this.messenger= messenger;
}public void promotionalNotification(){_messenger.sendMessage();
}
}
3. Method injection:
pass object data to the method we want to use directly in Notification class
public class Notification{public void promotionalNotification(Messenger messenger){messenger.sendMessage();
}
}