#5 Dependency Inversion Principle ['D' in SOLID]
Tags: solidprinciples, dependencyinversion, designprinciples
Published: 2024-07-01 17:30:40

**DIP - Dependency Inversion principle**
The Dependency Inversion Principle is the fifth principle in the Solid Design Principles.
1. High-Level Modules should not depend on Low-Level Modules. Both Should depend on abstraction.
2. Abstraction should not depend on details. Details should depend on Abstraction.

### High-Level Modules.
1. The High-Level Module contains important policy decisions and business logic.
2. They Should not be affected by changes in Low-Level Modules.

### Low-Level Modules.
1. Low-Level Modules contains implementation details.
2. Changes in Low-Level Modules should not affect High-Level Modules.

### Abstractions
1. Use Interfaces or Abstraction class to create an abstraction Layer.
2. High-level modules depend on this abstraction, allowing low-level module changes without affecting high-level logic.

**Violating DIP:**
```swift
class FileLogger {
    func log(message: String) {
        print("Loggin Message to file: \(message)")
    }
}

class UserService {
    private let logger = FileLogger()
    
    func createUser(name: String) {
        logger.log(message: "User \(name) Created.")
    }
}

// usage
let userService = UserService()
userService.createUser(name: "Vinay Kumar")
```

**Issues with Violating DIP:**
1. Tight Coupling:
   * UserService is tightly coupled to FileLogger, making it difficult to change the logging mechanism without modifying UserService.
2. Reduced Flexibility:
   * Switching to a different logging method (e.g., database logger, cloud logger) requires changing UserService.
3. Hard to Test:
   * Testing UserService requires an actual FileLogger, making it harder to isolate and test.

**Adhering to DIP:**
Using Protocol We can adhere to DIP.

```swift
protocol Logger {
    func log(message: String)
}

class FileLoggerDIP: Logger {
    func log(message: String) {
        print("Logging message to file: \(message)")
    }
}

class ConsoleLogger: Logger {
    func log(message: String) {
        print("Logging message to console: \(message)")
    }
}

class UserServiceDIP {
    let logger: Logger
    
    init(logger: Logger) {
        self.logger = logger
    }
    
    func createUser(name: String) {
        self.logger.log(message: "User \(name) Created")
    }
}

// usage
let fileLoggerDIP = FileLoggerDIP()
let consoleLogger = ConsoleLogger()
let userServiceDIPUsingFileLogger = UserServiceDIP(logger: fileLoggerDIP)
let userServiceDIPUsingConsoleLogger = UserServiceDIP(logger: consoleLogger)

userServiceDIPUsingFileLogger.createUser(name: "Vinay Kumar DIP FileLogger")
userServiceDIPUsingConsoleLogger.createUser(name: "Vinay Kumar DIP ConsoleLogger")
```

**Benefits of Adhering to DIP:**
1. Improved Maintainability:
   * Changes in low-level modules (like FileLogger) do not affect high-level modules (like UserService).
2. Enhanced Flexibility:
   * Easily switch between different logging mechanisms without changing the high-level module.
3. Increased Testability:
   * High-level modules can be tested with mock implementations of abstractions.

**Drawbacks of Adhering to DIP:**
1. Increased Complexity:
   * Requires creating additional interfaces or abstract classes.
2. More Boilerplate Code:
   * More code is needed to set up the abstractions.

**Mitigating Drawbacks:**
1. Balanced Approach:
   * Apply DIP where it provides significant benefits, balancing simplicity and extensibility.
2. Clear Documentation:
   * Maintain clear documentation to help developers understand the dependencies.
3. Use of Dependency Injection Frameworks:
   * Use frameworks to manage dependencies efficiently.

**Conclusion:**
 You can create more maintainable, understandable, and flexible software by thoughtfully understanding and applying the Dependency Inversion Principle. Ensuring that high-level modules depend on abstractions rather than low-level details promotes better software design and enhances the overall quality of the codebase.

[Interface Segregation Principle](https://dev.to/vinaykumar0339/4-interface-segregation-principle-i-in-solid-3g97)
[Single Responsibility Principle](https://dev.to/vinaykumar0339/1-single-responsibility-principle-s-in-solid-5fn9)
[Check My GitHub Swift Playground Repo.](https://github.com/vinaykumar0339/SolidDesignPrinciples)