hmlongco / Resolver

Swift Ultralight Dependency Injection / Service Locator framework
MIT License
2.15k stars 190 forks source link

[Question] Where to put Resolver in Presentation - Domain - Data architecture #92

Closed kientux closed 3 years ago

kientux commented 3 years ago

I'm currently implement layer architecture for my app, which will separate it into 3 layers:

The Data and Presentation depend on Domain.

I have an use case like this:

protocol ProductRepo {
    func getProductList(page: Int, limit: Int, query: String?,
                        completion: @escaping (Result<Paginated<Product>, DomainError>) -> Void)
}

struct GetProductListUseCase: UseCase {
    let repo: ProductRepo

    struct Params {
        var page: Int
        var limit: Int
        var searchQuery: String?
    }

    func execute(_ request: Params, completion: @escaping (Result<Paginated<Product>, DomainError>) -> Void) {
        repo.getProductList(page: request.page, limit: request.limit, query: request.searchQuery, completion: completion)
    }
}

and I want to inject ProductRepo (with something like ProductRepoImpl in the Data layer).

So anyone has recommendations to use Resolver for this architecture? Thank you.

hmlongco commented 3 years ago

As I wrote in Modern Dependency Injection in Swift, one can create an injection property wrapper for any DI system, so you're not going to be specifically tied to Resolver, though you'll probably have to rewrite your registrations if you were to switch.

Personally, I've tended towards using @Injected in our code where I work, as the app was specifically designed to rely on a dependency injection system and because I really dislike the boilerplate code associated with initializers.

class Test {

    var cache: UserImageCache
    var userService: UserServiceType
    var model: MainViewModel

    internal init(cache: UserImageCache, userService: UserServiceType, model: MainViewModel) {
        self.cache = cache
        self.userService = userService
        self.model = model
    }

}

As opposed to:

class Test {

     @Injected var cache: UserImageCache
     @Injected var userService: UserServiceType
     @Injected var model: MainViewModel

}

And, as mentioned, it makes registration much easier.

register { Test() }
// as opposed to
register { Test(cache: resolve(), userService: resolve(), model: resolve())}