Sobes.tech
Middle

What is the difference between dependency inversion and dependency injection?

sobes.tech AI

Answer from AI

Dependency Inversion Principle — one of the SOLID principles, states:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend on details; details should depend on abstractions.

Dependency Injection (DI) is a design pattern, one of the ways to implement dependency inversion. It involves passing dependencies (objects that a class depends on) from outside, instead of the class creating them itself.

Main differences:

  • DIC - a design principle, DI - a design pattern.
  • DIC - defines how relationships should be between high-level and low-level modules (dependence on abstractions).
  • DI - a method to implement these relationships. It is a specific technique for providing dependencies to an object.

Examples of dependency injection:

  • Constructor Injection: Dependencies are passed through the constructor.

    // Swift
    class UserFetcher {
        private let apiService: APIServiceProtocol // Dependency on abstraction
    
        init(apiService: APIServiceProtocol) { // Injection via constructor
            self.apiService = apiService
        }
    
        func fetchUsers() {
            // use apiService
        }
    }
    
    protocol APIServiceProtocol {
        // ...
    }
    
  • Property Injection: Dependencies are set through public properties (often using @IBOutlet or when an optional dependency is needed).

    // Swift
    class UserController: UIViewController {
        var userFetcher: UserFetcherProtocol? // Dependency can be set from outside
    
        override func viewDidLoad() {
            super.viewDidLoad()
            userFetcher?.fetchUsers()
        }
    }
    
    protocol UserFetcherProtocol {
        func fetchUsers()
    }
    
  • Method Injection: Dependencies are passed as method parameters.

    // Swift
    class DataProcessor {
        func process(data: Data, using parser: DataParserProtocol) { // Dependency is passed to method
            parser.parse(data)
        }
    }
    
    protocol DataParserProtocol {
        func parse(_ data: Data)
    }
    

Thus, dependency inversion is a goal (reducing coupling through abstractions), and dependency injection is a means (one of the ways to achieve this goal).

What is the difference between dependency inversion… - sobes.tech