High-level modules should not depend on low-level modules.
Both High-level & low-level should depend on abstractions.
In other words, Class should depend on abstractions (interface and abstract class) instead of concrete implementations. It makes our classes de-coupled with each other. If implementation changes then the class referring to it via abstraction won't change.
Bad Implementation :
Here, the LightSwitch class directly depends on a specific low-level module (LEDBulb).
If we want to switch to a different type of bulb (a new low-level module), you would need to modify the LightSwitch class, violating the Dependency Inversion Principle.
// High-level moduleclassLightSwitch{privateBulbbulb;publicLightSwitch(){this.bulb=newLEDBulb();// High-level module depends on a specific low-level module}publicvoidturnOn(){bulb.turnOn();}publicvoidturnOff(){bulb.turnOff();}}// Low-level moduleclassLEDBulb{publicvoidturnOn(){// Code to turn on an LED bulb}publicvoidturnOff(){// Code to turn off an LED bulb}}
Good Implementation :
Here, the LightSwitch class depends on an abstraction (Bulb interface) rather than a specific low-level module.
Different types of bulbs (like LEDBulb and CFLBulb) can be easily added without modifying the LightSwitch class, demonstrating adherence to the Dependency Inversion Principle.
// High-level moduleclassLightSwitch{privateBulbbulb;publicLightSwitch(Bulbbulb){this.bulb=bulb;// High-level module depends on an abstraction}publicvoidturnOn(){bulb.turnOn();}publicvoidturnOff(){bulb.turnOff();}}// Abstraction (Interface)interfaceBulb{voidturnOn();voidturnOff();}// Low-level modules implementing the abstractionclassLEDBulbimplementsBulb{publicvoidturnOn(){// Code to turn on an LED bulb}publicvoidturnOff(){// Code to turn off an LED bulb}}classCFLBulbimplementsBulb{publicvoidturnOn(){// Code to turn on an CFL bulb}publicvoidturnOff(){// Code to turn off an CFL bulb}}