Swift 如何实现符合具有类型约束的协议的泛型基类,并为这些泛型类型实现工厂?

Swift 如何实现符合具有类型约束的协议的泛型基类,并为这些泛型类型实现工厂?,swift,generics,protocols,factory,Swift,Generics,Protocols,Factory,我试图在我的项目中实现存储库模式。我希望设计足够灵活,以便将来需要时可以交换底层实现。例如,我希望能够支持Realm,但如果需要的话,可以将其与核心数据交换。我还想为测试实施假货 我用fakes开始实现,我想做的是用符合存储库协议的通用约束实现一个FakeRepository基类 请注意,为了使文章尽可能简短,我省略了一些实现细节 protocol Repository { associatedtype Item var count: Int { get } func

我试图在我的项目中实现存储库模式。我希望设计足够灵活,以便将来需要时可以交换底层实现。例如,我希望能够支持Realm,但如果需要的话,可以将其与核心数据交换。我还想为测试实施假货

我用fakes开始实现,我想做的是用符合存储库协议的通用约束实现一个FakeRepository基类

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

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