swift - 如何实现符合具有类型约束的协议(protocol)的通用基类并为这些通用类型实现工厂?

标签 swift generics protocols factory

我正在尝试在我的项目中实现存储库模式。我希望设计足够灵活,以便我可以在将来需要时更换底层实现。例如,我希望能够支持 Realm,但在需要时能够将其替换为 Core Data。我还想实现假货进行测试。

我从伪造开始实现,我想做的是实现一个 FakeRepository 基类,它具有符合 Repository 协议(protocol)的通用约束。

请注意,我省略了一些实现细节以使文章尽可能简短。

protocol Repository {
    associatedtype Item

    var count: Int { get }

    func item(at index: Int) -> Item
}

class FakeRepository<Model>: Repository where Model: Identifiable {
    private var items: [Model] = []

    var count: Int { items.count }

    func item(at index: Int) -> Model {
        return items[index]
    }
}

我还想为我打算支持的每个模型定义一个协议(protocol)。例如,一个 UserRepository。

struct User: Identifiable {
    let id: Int
    let name: String
}

protocol UserRepository: Repository where Item == User { }

现在我所要做的就是定义一个具体的 FakeUserRepository,我不需要实现任何东西,因为所有的工作都已经完成了。

class FakeUserRepository: FakeRepository<User>, UserRepository { }

我遇到的麻烦是当我到达工厂模式实现时。我想做的是这样的事情,但是工厂协议(protocol)无法编译,因为 UserRepository 有相关的类型要求。

protocol UserRepositoryFactory {
    func makeRepository() -> UserRepository // DOES NOT COMPILE
}

struct FakeUserRepositoryFactory: UserRepositoryFactory {
    func makeRepository() -> UserRepository {
        return FakeUserRepository()
    }
}

struct CoreDataUserRepositoryFactory: UserRepositoryFactory {
    func makeRepository() -> UserRepository {
        return CoreDataUserRepository()
    }
}

然后我想传递一个包含我所有工厂的依赖容器。

struct DependencyContainer {
    let userRepositoryFactory: UserRepositoryFactory
}

我尝试的另一种解决方案是这样的:

protocol Repository2 {
    associatedtype Item
    func item(at index: Int) -> Item
}

class Repository2Base<Model>: Repository2 {
    func item(at index: Int) -> Model {
        fatalError()
    }
}

class FakeRepository2<Model>: Repository2Base<Model> {
    var items: [Model] = []
    override func item(at index: Int) -> Model {
        return items[index]
    }
}

protocol UserRepositoryFactory2 {
    func makeRepository() -> Repository2Base<User>
}

class FakeUserRepositoryFactory2: UserRepositoryFactory2 {
    func makeRepository() -> Repository2Base<User> {
        return FakeRepository2<User>()
    }
}

现在它可以编译并运行良好,但我不喜欢我必须调用 fatalError() 才能编译。这似乎是一个黑客。是否有一种优雅的方式来实现我的目标?

最佳答案

我不喜欢混合继承和泛型,我想说这就是你必须调用 fatalError()

的原因

试试这个:

  1. 首先是Repository 协议(protocol)
protocol Repository {
    associatedtype Item: Identifiable
    func item(at index: Int) -> Item
    init() 
}

class FakeRepository<Item: Identifiable>: Repository {
    var items: [Item]
    func item(at index: Int) -> Item {
        return items[index]
    }
    
    required init() { // notice that it it required
        items = []
    }
}

我在这里添加了 init() 因为我想要 FakeRepositoryFactory 创建任何 存储库

  1. 然后是工厂:

public class SomeFakeRepositoryFactory {
    public init() { }
    public func makeRepository<Repo: Repository>() -> Repo {
        return Repo()
    }
}

你可以这样使用它:


struct User: Identifiable {
    let id: Int
    let name: String
}

struct Car: Identifiable {
    let id: Int
    let name: String
}


let user = User(id: 1, name: "Robert")
let factory = SomeFakeRepositoryFactory()
var userRepository: FakeRepository<User> = factory.makeRepository()
userRepository.items = [user]
userRepository.items.forEach { print($0.name) } // prints "Robert"

let car = Car(id: 1, name: "Delorean")
var carRepository = factory.makeRepository() as FakeRepository<Car>
carRepository.items = [car]
carRepository.items.forEach { print($0.name) } // prints Delorean

关于swift - 如何实现符合具有类型约束的协议(protocol)的通用基类并为这些通用类型实现工厂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62510813/

相关文章:

ios - 使用 header 和参数发出 get 请求时出现 alamofire 499

java - 泛型树,自界泛型

ios - 允许子类使用子类委托(delegate)

iphone - Objective C 中的转发类和协议(protocol)

ios - 我的 TableViewCell 自定义类中的 IbOutlet 从未被初始化

ios - 如何使用 iCloud 同步 iOS 和 OS X 应用程序?

ios - 如何在 Swift 中使用 JTCalendar?

java - 如何获取字段的泛型参数类

java - Collection.add 和 Collection.addAll 中的一些问题

ios - 同时在两个不同的类中调用协议(protocol)