# Resolver: Injection Strategies ## Terminology There are five primary ways of performing dependency injection using Resolver: 1. [Interface Injection](#interface) 2. [Property Injection](#property) 3. [Constructor Injection](#constructor) 4. [Method Injection](#method) 5. [Service Locator](#locator) 6. [Annotation](#annotation) (NEW) The names and numbers come from the *Inversion of Control* design pattern. For a more thorough discussion, see the classic arcticle by [Martin Fowler](https://martinfowler.com/articles/injection.html). Here I'll simply provide a brief description and an example of implementing each using Resolver. ## 1. Interface Injection #### Definition The first injection technique is to define a interface for the injection, and injecting that interface into the class or object using Swift extensions. #### The Class ```swift class XYZViewModel { lazy var fetcher: XYZFetching = getFetcher() lazy var service: XYZService = getService() func load() -> Data { return fetcher.getData(service) } } ``` #### The Dependency Injection Code ```swift extension XYZViewModel: Resolving { func getFetcher() -> XYZFetching { return resolver.resolve() } func getService() -> XYZService { return resolver.resolve() } } func setupMyRegistrations { register { XYZFetcher() as XYZFetching } register { XYZService() } } ``` Note that you still want to call `resolve()` within `getFetcher()` and `getService()` , otherwise you're back to tightly-coupling the dependent classes and bypassing the resolution registration system. #### Pros * Lightweight. * Hides dependency injection system from class. * Useful for classes like UIViewController where you don't have access during the initialization process. #### Cons * Writing an accessor function for every service that needs to be injected. ## 2. Property Injection #### Definition Property Injection exposes its dependencies as properties, and it's up to the Dependency Injection system to make sure everything is setup prior to any methods being called. #### The Class ```swift class XYZViewModel { var fetcher: XYZFetching! var service: XYZService! func load() -> Data { return fetcher.getData(service) } } ``` #### The Dependency Injection Code ```swift func setupMyRegistrations { register { XYZViewModel() } .resolveProperties { (resolver, model) in model.fetcher = resolver.optional() // Note property is an ImplicitlyUnwrappedOptional model.service = resolver.optional() // Ditto } } func setupMyRegistrations { register { XYZFetcher() as XYZFetching } register { XYZService() } } ``` #### Pros * Clean. * Also fairly lightweight. #### Cons * Exposes internals as public variables. * Harder to ensure that an object has been given everything it needs to do its job. * More work on the registration side of the fence. ## 3. Constructor Injection #### Definition A Constructor is the Java term for a Swift Initializer, but the idea is the same: Pass all of the dependencies an object needs through its initialization function. #### The Class ```swift class XYZViewModel { private var fetcher: XYZFetching private var service: XYZService init(fetcher: XYZFetching, service: XYZService) { self.fetcher = fetcher self.service = service } func load() -> Image { let data = fetcher.getData(token) return service.decompress(data) } } ``` #### The Dependency Injection Code ```swift func setupMyRegistrations { register { XYZViewModel(fetcher: resolve(), service: resolve()) } register { XYZFetcher() as XYZFetching } register { XYZService() } } ``` #### Pros * Ensures that the object has everything it needs to do its job, as the object can't be constructed otherwise. * Hides dependencies as private or internal. * Less code needed for the registration factory. #### Cons * Requires object to have initializer with all parameters needed. * More boilerplace code needed in the object initializer to transfer parameters to object properties. ## 4. Method Injection #### Definition This is listed for completeness, even though it's not a pattern that uses Resolver directly. Method Injection is pretty much what it says, injecting the object needed into a given method. #### The Class ```swift class XYZViewModel { func load(fetcher: XYZFetching, service: XYZService) -> Data { return fetcher.getData(service) } } ``` #### The Dependency Injection Code You've already seen it. In the load function, the service object is passed into the fetcher's getData method. #### Pros * Allows callers to configure the behavior of a method on the fly. * Allows callers to construct their own behaviors and pass them into the method. #### Cons * Exposes those behaviors to all of the classes that use it. #### Note In Swift, passing a closure into a method could also be considered a form of Method Injection. ## 5. Service Locator #### Definition A Service Locator is basically a service that locates the resources and dependencies an object needs. Technically, Service Locator is its own Design Pattern, distinct from Dependency Injection, but Resolver supports both and the Service Locator pattern is particularly useful when supporting view controllers and other classes where the initialization process is outside of your control. (See [Storyboards](https://github.com/hmlongco/Resolver/blob/master/Documentation/Storyboards.md).) #### The Class ```swift class XYZViewModel { var fetcher: XYZFetching = Resolver.resolve() var service: XYZService = Resolver.resolve() func load() -> Data { return fetcher.getData(service) } } ``` #### The Dependency Injection Code ```swift func setupMyRegistrations { register { XYZFetcher() as XYZFetching } register { XYZService() } } ``` #### Pros * Less code. * Useful for classes like UIViewController where you don't have access during the initialization process. #### Cons * Exposes the dependency injection system to all of the classes that use it. ## 6. Annotation #### Definition Annotation uses comments or other metadata to indication that dependency injection is required. As of Swift 5.1, we can now perform annotation using Property Wrappers. (See [Annotation](https://github.com/hmlongco/Resolver/blob/master/Documentation/Annotation.md).) #### The Class ```swift class XYZViewModel { @Injected var fetcher: XYZFetching @Injected var service: XYZService func load() -> Data { return fetcher.getData(service) } } ``` #### The Dependency Injection Code ```swift func setupMyRegistrations { register { XYZFetcher() as XYZFetching } register { XYZService() } } ``` #### Pros * Less code. * Hides the specifics of the injection system. One could easily make an Injected property wrapper to support any DI system. * Useful for classes like UIViewController where you don't have access during the initialization process. #### Cons * Exposes the fact that a dependency injection system is used. ## Additonal Resources This just skims the surface. For a more in-depth look at the pros and cons, see: [Inversion of Control Containers and the Dependency Injection pattern ~ Martin Fowler](https://martinfowler.com/articles/injection.html).