gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 06:15:28 25 4
gpt4 key购买 nike

我正在尝试在我的项目中实现存储库模式。我希望设计足够灵活,以便我可以在将来需要时更换底层实现。例如,我希望能够支持 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com