我正在尝试在我的项目中实现存储库模式。我希望设计足够灵活,以便我可以在将来需要时更换底层实现。例如,我希望能够支持 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()
试试这个:
- 首先是
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
创建任何 存储库
- 然后是工厂:
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/