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

时间:2018-06-11 10:14:23

标签: swift repository-pattern

我一直在对存储库模式进行一些研究,因为我想使用它正在开发的新项目。但是我遇到了使用泛型的问题

我一直在这里以此指南为例

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
    }
}

这不再适用。我现在收到错误说

  

协议'存储库'只能用作通用约束因为   它有自我或相关的类型要求

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

任何帮助都会得到很多帮助

1 个答案:

答案 0 :(得分:2)

您还需要将其他所有内容都设为通用:

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中,你不能使用具有相关类型的协议作为属性/参数的类型等。它应该使你的代码更加类型安全。