dimanche 11 novembre 2018

Protocols with associated type and factory pattern?

My data access layer consists of a generic Repository protocol

protocol Repository {
    associatedtype T
    func getAll() -> Promise<[T]>
}

and its concrete implementation:

class FirebaseRepository<T: Model>: Repository {
    func getAll() -> Promise<[T]> {
        fatalError()
    }
}

Basically, Repository can be RestRepository, FirebaseRepository, PlistRepositry etc. Repository is used by the business logic:

/// My business logic
class ModelService<T: Repository> {
    private let repository: T

    public init(repository: T) {
        self.repository = repository
    }
}

The problem comes when I'm trying to apply a factory pattern to a repository. Here's what I came in first:

/// Returns a concrete Repository implementation
class RepositoryFactory {
    func makeRepository<T: Model>(type: T.Type) -> Repository {
        return FirebaseRepository<T>()
    }
}

and this definitely gets a compiler error:

Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements

The only viable option I came to is this:

func makeRepository<T: Model>(type: T.Type, U: Repository) -> U {
    return FirebaseRepository<T>() as! U
}

but as you understand, the force optional unwrapping is not acceptable in the production code.

How to make protocols with associated types work with factory design pattern?

Aucun commentaire:

Enregistrer un commentaire