In this example:
The Light and Fan classes are concrete implementations of the Device interface.
The DeviceController class is the high-level module that operates a device. It depends on the Device abstraction.
By adhering to the Dependency Inversion Principle, the DeviceController class is not concerned with the specific details of how each device turns on or off. It relies on the abstraction, allowing for flexibility. If a new type of device is introduced, you can create a new class implementing the Device interface without modifying the DeviceController class. This promotes a more modular and maintainable codebase.
How break DIP in above code
To break the Dependency Inversion Principle (DIP) in the given code, you would modify it so that the **high-level module (DeviceController) depends on concrete implementations (Light, Fan) instead of the abstraction (Device). The DIP ensures that high-level modules depend on abstractions, not on concrete implementations.
DeviceController class depends on the Device interface (abstraction). This means it can work with any Device implementation, such as Light or Fan, without knowing their details. This adheres to the DIP because:- High-level module:
DeviceControllerdepends on the abstractionDevice, not the concrete classesLightorFan.
Breaking DIP: High-level module depends on concrete classes
To break the DIP:
- Remove the dependency on the
Deviceinterface. - Make
DeviceControllerdirectly depend on the specific implementations, likeLightorFan.
Example:
class DeviceController {
private final Light light; // Direct dependency on a concrete implementation
public DeviceController() {
this.light = new Light(); // Instantiating a concrete class inside the controller
}
public void operateDevice() {
// Directly calling methods on the Light class
light.turnOn();
// Additional logic if needed
light.turnOff();
}
}
What's wrong here:
DeviceControlleris tightly coupled to theLightclass.- You cannot reuse
DeviceControllerwith another device (e.g.,Fan) without modifying its code.
- You cannot reuse
- Violates the Open/Closed Principle:
- To add support for another
DevicelikeFan, you must modifyDeviceController.
- To add support for another
- Reduces flexibility:
- No way to dynamically pass different
Deviceimplementations at runtime.
- No way to dynamically pass different
Consequences of Breaking DIP
- Reduced Testability:
- You can't substitute a mock
Devicefor testing purposes becauseDeviceControlleris tied to specific implementations.
- You can't substitute a mock
- Tight Coupling:
DeviceControllernow relies on concrete classes, which makes it harder to maintain and extend.
- Violated Dependency Injection:
- Dependency injection is no longer possible since
DeviceControllerinstantiates theLightobject directly.
- Dependency injection is no longer possible since
Restoring DIP
To fix this and restore adherence to DIP, you would:
- Depend on the abstraction (
Device). - Use dependency injection to pass the implementation (
LightorFan) intoDeviceController.
Example:
class DeviceController {
private final Device device;
public DeviceController(Device device) {
this.device = device; // Dependency injection
}
public void operateDevice() {
device.turnOn();
device.turnOff();
}
}
Now, DeviceController is flexible and adheres to DIP.
No comments:
Post a Comment