Swift 如何实现符合具有类型约束的协议的泛型基类,并为这些泛型类型实现工厂?
我试图在我的项目中实现存储库模式。我希望设计足够灵活,以便将来需要时可以交换底层实现。例如,我希望能够支持Realm,但如果需要的话,可以将其与核心数据交换。我还想为测试实施假货 我用fakes开始实现,我想做的是用符合存储库协议的通用约束实现一个FakeRepository基类 请注意,为了使文章尽可能简短,我省略了一些实现细节Swift 如何实现符合具有类型约束的协议的泛型基类,并为这些泛型类型实现工厂?,swift,generics,protocols,factory,Swift,Generics,Protocols,Factory,我试图在我的项目中实现存储库模式。我希望设计足够灵活,以便将来需要时可以交换底层实现。例如,我希望能够支持Realm,但如果需要的话,可以将其与核心数据交换。我还想为测试实施假货 我用fakes开始实现,我想做的是用符合存储库协议的通用约束实现一个FakeRepository基类 请注意,为了使文章尽可能简短,我省略了一些实现细节 protocol Repository { associatedtype Item var count: Int { get } func
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]
}
}
现在我所要做的就是定义一个具体的FakeUserRepository,我不需要实现任何东西,因为所有的工作都已经完成了
class FakeUserRepository: FakeRepository<User>, UserRepository { }
然后我想传递一个依赖性容器和我所有的工厂
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>()
}
}
协议存储2{
关联类型项
func项(在索引:Int处)->item
}
类Repository2数据库:Repository2{
func项(索引:Int)->模型{
法塔莱罗()
}
}
FakerRepository2类:Repository2数据库{
变量项:[模型]=[]
覆盖func项(索引:Int)->Model{
退货项目[索引]
}
}
协议UserRepositoryFactory2{
func makeRepository()->Repository2Base
}
类FakeUserRepositoryFactory2:UserRepositoryFactory2{
func makeRepository()->Repository2Base{
返回FakeRepository2()
}
}
现在这可以很好地编译,但我不喜欢仅仅为了编译而调用
fatalError()
。这看起来像一个黑客。有没有一种优雅的方法可以实现我的目标?我不喜欢将继承和泛型混为一谈,我想说这就是为什么必须调用fatalError()
试试这个:
存储库
协议
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
结构用户:可识别{
让id:Int
let name:String
}
结构车:可识别{
让id:Int
let name:String
}
let user=user(id:1,名称:“Robert”)
let factory=SomeFakeRepositoryFactory()
var userRepository:FakeRepository=factory.makeRepository()
userRepository.items=[user]
userRepository.items.forEach{print($0.name)}//打印“Robert”
let car=汽车(id:1,名称:“Delorean”)
var carRepository=factory.makeRepository()作为FakeRepository
carRepository.items=[car]
carRepository.items.forEach{print($0.name)}//prints Delorean
在这一点上,我认为实现我想要的是不可能的。我需要一个更多态的实现,在编译时不需要知道存储库和工厂类型。相关的类型要求使得真正的工厂模式实现变得不可能!等等:)@RobertCrabtree那样更好吗?工厂类型仍然需要在编译时知道,但工厂不再绑定到单一类型的存储库。理想情况下,工厂方法不会有任何存储库类型约束。这仍然是一个编译时解决方案。谢谢,但我认为这是不可能的。当然,如果你想让工厂创建存储库,你必须在某个时候告诉编译器嘿,罗布,很抱歉这里的垃圾邮件,但我真的需要你的帮助!:D检查你的linkedin
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>()
}
}
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 = []
}
}
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