Swift 协议引用自身和相关类型



我有一个带有以下代码的责任链模式的经典实现:

protocol Request {
var firstName: String? { get }
var lastName: String? { get }
var email: String? { get }
var password: String? { get }
var repeatedPassword: String? { get }
} 
protocol Handler {
var next: Handler? { get }
func handle(_ request: Request) -> LocalizedError?
}
class BaseHandler: Handler {
var next: Handler?
init(with handler: Handler? = nil) {
self.next = handler
}
func handle(_ request: Request) -> LocalizedError? {
return next?.handle(request)
}
}

因此,我可以创建一个PermissionHandler,LocationHandler,LoginHandler,SignupHandler并将它们组合在链中。目前为止,一切都好。

现在我想为其他目的创建一个责任链,假设一个具有不同类型的 MediaContentHandler 的 MediaContentPlayer CoR,我想使用泛型重构和重用基本代码。

所以我从处理程序协议开始:

protocol Handler {
associatedtype HandlerRequest
var next: Handler? { get }
func handle(_ request: HandlerRequest) -> LocalizedError?
}

但是我收到错误"协议'处理程序'只能用作通用约束,因为它具有 Self 或关联的类型要求"。

使用 associatedtype 时,有没有办法在协议本身中引用协议?还是另一种使上述代码不依赖于特定类型的方法?

你会照顾这样的事情:

protocol Handler {
// ...
var next: some Handler<HandlerRequest == Self.HandlerRequest>?  { get }
// ...
}

这里的问题是 Swift (尚(不支持不透明的返回类型,这些返回类型是具有关联类型的协议。

此限制的解决方案是对next属性使用类型橡皮擦:

protocol Handler {
associatedtype HandlerRequest
// shift the generic from a protocol with associated type to a generic struct
var next: AnyHandler<HandlerRequest>? { get }
func handle(_ request: HandlerRequest) -> LocalizedError?
}
struct AnyHandler<HandlerRequest> {
private var _handle: (HandlerRequest) -> LocalizedError?
private var _next: () -> AnyHandler<HandlerRequest>?
init<H: Handler>(_ handler: H) where H.HandlerRequest == HandlerRequest {
_next = { handler.next }
_handle = handler.handle
}
}
extension AnyHandler: Handler {
var next: AnyHandler<HandlerRequest>? { return _next() }
func handle(_ request: HandlerRequest) -> LocalizedError? {
return _handle(request)
}
}

这样,您既可以使协议受益,也可以将next属性绑定到所需的处理程序请求类型。

作为使用协议的额外好处,您仍然可以从基类中受益默认实现:

extension Handler {
func handle(_ request: HandlerRequest) -> LocalizedError? {
return next?.handle(request)
}
}

这就是 Swift 协议的酷炫之处,它们允许你通过改进多态性的概念来尽可能避免类并尽可能多地使用值类型。


使用示例:

struct LoginHandler: Handler {
var next: AnyHandler<AccountRequest>?
func handle(_ request: AccountRequest) -> LocalizedError? {
// do the login validation
}
}
struct SignupHandler: Handler {
var next: AnyHandler<AccountRequest>?
func handle(_ request: AccountRequest) -> LocalizedError? {
// do the signup validation
}
}
extension Handler {
// Helper function to easily create a type erased AnyHandler instance    
func erase() -> AnyHandler<HandlerRequest> {
return AnyHandler(self)
}
}
// now let's put the handers to work:
let loginHandler = LoginHandler()
let signupHandler = SignupHandler(next: loginHandler.erase())
let someOtherAccountHandler = SomeOtherAccountHandler(next: signupHandler.erase())

我会使用以下

protocol Handler {
associatedtype HandlerRequest
associatedtype NextHandler: Handler
var next: Self.NextHandler? { get }
func handle(_ request: HandlerRequest) -> LocalizedError?
}

最新更新