Как я могу зарегистрировать 2 зависимости с одним и тем же абстрактным интерфейсом в моем фабричном преобразователе? - PullRequest
1 голос
/ 07 апреля 2020

У меня есть контейнер зависимостей, который выглядит следующим образом -

public protocol DependencyContainer {
  typealias FactoryClosure = (Self) -> AnyObject
  func register<Service>(type: Service.Type, closure: @escaping FactoryClosure)
  func resolve<Service>(type: Service.Type) -> Service
}
public final class CoreDependencyContainer: DependencyContainer {

  private var services: Dictionary<ObjectIdentifier, FactoryClosure> = [:]

  public func register<Service>(type: Service.Type, closure: @escaping FactoryClosure) {
    services[ObjectIdentifier(type)] = closure
  }

  public func resolve<Service>(type: Service.Type) -> Service {
    if let service = services[ObjectIdentifier(type)]?(self) as? Service {
      return service
    }
    preconditionFailure("Could not resolve service for \(type)")
  }

}

У меня есть несколько зарегистрированных служб:

dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
  let httpClient = container.resolve(type: HTTPClient.self)
    return RemoteImageDataLoader(client: httpClient)
})

Я хочу зарегистрировать 2 службы которые соответствуют абстрактному типу RemoteImageDataLoader.

dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
  let httpClient = container.resolve(type: HTTPClient.self)
    return RemoteImageDataLoader(client: httpClient)
})

dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
  let httpClient = container.resolve(type: AuthenticatedHTTPClient.self)
    return RemoteImageDataLoader(client: httpClient)
})

Это, очевидно, не сработает, поскольку вторая запись заменит первую в словаре services.

Я пытался создать typealias использовать вместо этого, однако это не работает.

dependencies.register(type: RemoteImageDataLoader.self, closure: { container in
  let httpClient = container.resolve(type: HTTPClient.self)
    return RemoteImageDataLoader(client: httpClient)
})

typealias AuthRemoteImageLoader = RemoteImageDataLoader

dependencies.register(type: AuthRemoteImageLoader.self, closure: { container in
  let httpClient = container.resolve(type: AuthenticatedHTTPClient.self)
    return RemoteImageDataLoader(client: httpClient)
})

Как я могу зарегистрировать 2-ую зависимость в этом случае?

Я бы хотел избежать создания 2 версий RemoteImageDataLoader единственное отличие - внедренный HTTPClient экземпляр.

1 Ответ

1 голос
/ 07 апреля 2020

Это не работает в данный момент, так как вы используете ObjectIdentifier в качестве ключа в своем словаре, который typealias не меняется.

Вы в основном регистрируете один и тот же объект дважды.

Создать пустой протокол, соответствующий тому же интерфейсу. Вам также нужно будет расширить ваш интерфейс, чтобы он соответствовал вашему новому, пустому интерфейсу, в противном случае ваш метод resolve выдаст preconditionFailure

protocol AuthRemoteImageLoader: RemoteImageDataLoader { }
extension RemoteImageDataLoader: AuthRemoteImageLoader { }

Вы также можете рассмотреть возможность использования обобщений для указания интерфейса HTTPClient. использовать и расширить RemoteImageDataLoader, чтобы действовать соответственно в зависимости от типа клиента.

...