Swift - 使用泛型实现存储库模式

Swift - implementing repository pattern with generics

我一直在研究存储库模式,因为我想在我正在从事的新项目中使用它。但是我在使用泛型时遇到问题

我一直以本指南为例

https://medium.com/@frederikjacques/repository-design-pattern-in-swift-952061485aa

这对它的解释相当不错。然而,该指南遗漏了一个重要的细节……即使用泛型的依赖注入。

在示例代码中,他展示了这个

class ArticleFeedViewModel {
  let articleRepo:ArticleRepository
  init( articleRepo:ArticleRepository = WebArticleRepository() ) {

    self.articleRepo = articleRepo
  }
}

如果您不使用泛型,它可以正常工作。但是一旦您将 ArticleRepository 更改为 Repository 示例...所以从

protocol ArticleRepository {
    func getAll() -> [Article]
    func get( identifier:Int ) -> Article?
    func create( article:Article ) -> Bool
    func update( article:Article ) -> Bool
    func delete( article:Article ) -> Bool
}

至此

protocol Repository {

  associatedtype T

  func getAll() -> [T]
  func get( identifier:Int ) -> T?
  func create( a:T ) -> Bool
  func update( a:T ) -> Bool
  func delete( a:T ) -> Bool

}

我无法再让依赖注入工作。所以如果我要尝试重新创建上面显示的模型。

class WebArticleRepository: Repository {
    func getAll() -> [Article] {
        return [Article()]
    }

    func get(identifier: Int) -> Article? {
        return Article()
    }

    func create(a: Article) -> Bool {
        return true
    }

    func update(a: Article) -> Bool {
        return false
    }

    func delete(a: Article) -> Bool {
        return true
    }
}

class ArticleFeedViewModel {
    let articleRepo:Repository
    init( articleRepo:Repository = WebArticleRepository() ) {
        self.articleRepo = articleRepo
    }
}

这不再有效。我现在收到一条错误消息

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

关于我在这里做错了什么的任何想法。似乎添加 associatedType 会导致它停止工作。我真的很想让这个功能正常工作,因为我希望能够根据应用程序的当前状态注入本地或基于 Web 的存储库模式

如有任何帮助,我们将不胜感激

您还需要使其他所有内容通用:

protocol Repository {

    associatedtype RepositoryType

    func getAll() -> [RepositoryType]
    func get( identifier:Int ) -> RepositoryType?
    func create( a:RepositoryType ) -> Bool
    func update( a:RepositoryType ) -> Bool
    func delete( a:RepositoryType ) -> Bool

}

class WebArticle { }

class WebArticleRepository: Repository {
    typealias RepositoryType = WebArticle

    func getAll() -> [WebArticle] {
        return [WebArticle()]
    }

    func get(identifier: Int) -> WebArticle? {
        return WebArticle()
    }

    func create(a: WebArticle) -> Bool {
        return true
    }

    func update(a: WebArticle) -> Bool {
        return false
    }

    func delete(a: WebArticle) -> Bool {
        return true
    }
}

class ArticleFeedViewModel<T : Repository> {
    let articleRepo: T
    init( articleRepo: T) {

        self.articleRepo = articleRepo
    }
}

// you cannot have the optional parameter in the init, instead, you can extract the following line to a method
ArticleFeedViewModel(articleRepo: WebArticleRepository())

在 Swift 中,您不能使用具有关联类型的协议作为 property/parameter 等的类型。它应该使您的代码更加类型安全。