具有关联类型和工厂模式的协议?
Protocols with associated type and factory pattern?
我的数据访问层包含一个通用的Repository
协议
protocol Repository {
associatedtype T
func getAll() -> Promise<[T]>
}
及其具体实现:
class FirebaseRepository<T: Model>: Repository {
func getAll() -> Promise<[T]> {
fatalError()
}
}
基本上,Repository
可以是RestRepository
、FirebaseRepository
、PlistRepositry
等。Repository用于业务逻辑:
/// My business logic
class ModelService<T: Repository> {
private let repository: T
public init(repository: T) {
self.repository = repository
}
}
当我尝试将工厂模式应用于存储库时出现问题。这是我先来的:
/// Returns a concrete Repository implementation
class RepositoryFactory {
func makeRepository<T: Model>(type: T.Type) -> Repository {
return FirebaseRepository<T>()
}
}
这肯定会导致编译器错误:
Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements
我唯一可行的选择是:
func makeRepository<T: Model>(type: T.Type, U: Repository) -> U {
return FirebaseRepository<T>() as! U
}
但如您所知,强制可选展开在生产代码中是不可接受的。
如何使具有关联类型的协议与工厂设计模式一起工作?
您可以使用类型擦除。这是一个例子:
protocol CustomProtocol {
associatedtype AssociatedType
func foo(argument: AssociatedType)
func bar() -> AssociatedType
}
如果你想直接使用CustomProtocol
,你会收到你的错误:
let array = [CustomProtocol]()
Protocol 'CustomProtocol' can only be used as a generic constraint because it has Self or associated type requirements
因此您可以使用相同的技巧,就像 Swift 对它们的序列所做的那样:
public struct AnyCustomProtocol<T>: CustomProtocol {
func bar() -> T {
fatalError("Needs implementation")
}
func foo(argument: T) {
}
}
let array = [AnyCustomProtocol<Any>]() // works fine
在这种情况下,您的问题解决方案看起来像这样:
class Promise<T> {
}
protocol Model {
}
protocol Repository {
associatedtype T
func getAll() -> Promise<[T]>
}
class FirebaseRepository<T: Model>: AnyRepository<T> {
override func getAll() -> Promise<[T]> {
fatalError()
}
}
class AnyRepository<T>: Repository {
func getAll() -> Promise<[T]> {
fatalError()
}
}
class RepositoryFactory {
func makeRepository<T: Model>(type: T.Type) -> AnyRepository<T> {
return FirebaseRepository<T>()
}
}
__
如需进一步阅读,您可以查看 this and Official docs on Generics
我的数据访问层包含一个通用的Repository
协议
protocol Repository {
associatedtype T
func getAll() -> Promise<[T]>
}
及其具体实现:
class FirebaseRepository<T: Model>: Repository {
func getAll() -> Promise<[T]> {
fatalError()
}
}
基本上,Repository
可以是RestRepository
、FirebaseRepository
、PlistRepositry
等。Repository用于业务逻辑:
/// My business logic
class ModelService<T: Repository> {
private let repository: T
public init(repository: T) {
self.repository = repository
}
}
当我尝试将工厂模式应用于存储库时出现问题。这是我先来的:
/// Returns a concrete Repository implementation
class RepositoryFactory {
func makeRepository<T: Model>(type: T.Type) -> Repository {
return FirebaseRepository<T>()
}
}
这肯定会导致编译器错误:
Protocol 'Repository' can only be used as a generic constraint because it has Self or associated type requirements
我唯一可行的选择是:
func makeRepository<T: Model>(type: T.Type, U: Repository) -> U {
return FirebaseRepository<T>() as! U
}
但如您所知,强制可选展开在生产代码中是不可接受的。
如何使具有关联类型的协议与工厂设计模式一起工作?
您可以使用类型擦除。这是一个例子:
protocol CustomProtocol {
associatedtype AssociatedType
func foo(argument: AssociatedType)
func bar() -> AssociatedType
}
如果你想直接使用CustomProtocol
,你会收到你的错误:
let array = [CustomProtocol]()
Protocol 'CustomProtocol' can only be used as a generic constraint because it has Self or associated type requirements
因此您可以使用相同的技巧,就像 Swift 对它们的序列所做的那样:
public struct AnyCustomProtocol<T>: CustomProtocol {
func bar() -> T {
fatalError("Needs implementation")
}
func foo(argument: T) {
}
}
let array = [AnyCustomProtocol<Any>]() // works fine
在这种情况下,您的问题解决方案看起来像这样:
class Promise<T> {
}
protocol Model {
}
protocol Repository {
associatedtype T
func getAll() -> Promise<[T]>
}
class FirebaseRepository<T: Model>: AnyRepository<T> {
override func getAll() -> Promise<[T]> {
fatalError()
}
}
class AnyRepository<T>: Repository {
func getAll() -> Promise<[T]> {
fatalError()
}
}
class RepositoryFactory {
func makeRepository<T: Model>(type: T.Type) -> AnyRepository<T> {
return FirebaseRepository<T>()
}
}
__
如需进一步阅读,您可以查看 this and Official docs on Generics