协议继承 - 覆盖方法参数

Posted

技术标签:

【中文标题】协议继承 - 覆盖方法参数【英文标题】:Protocol Inheritance - overriding method parameters 【发布时间】:2021-02-14 12:01:48 【问题描述】:

我正在尝试将我的设计转换为pop。但是,我被卡住了,并且已经有一堆线程可以用于我的方法 - 虽然不是这个问题的重复 - 显然它们都是死胡同。

我的问题是,有没有办法覆盖从另一个协议继承的协议方法的参数类型?

struct Books: Codable 

protocol Listener 
    func listen(_ param: Codable)


protocol BooksListener: Listener 
    func listen(_ param: Books)



class MyClass: BooksListener 
    // I want only this one to required with the type.
    func listen(_ param: Books) 
        <#code#>
    
    
    func listen(_ param: Codable) 
        <#code#>
    

我进行了研究,我相信这不是协议的工作方式。我只是在寻求解决方案。

我尝试将associatedType 添加到Listener 并将其用作listen(_:) 中的类型。但是这个解决方案限制任何类必须符合从Listener 继承的多个协议。详情可见here

【问题讨论】:

"但显然不是最佳实践,因为类似的类和协议不共享任何祖先。"我不同意类似的类必须共享一个祖先。您可以过度干燥代码。抽象应该始终服务于一个目的。使事情变得非常复杂以消除少量清晰的代码对程序的伤害大于它的帮助。但是这里可能有一些价值,所以让我们探索一下。 :D (另外,从头开始构建,我已经重新创建了你描述的每一个问题。其中一些无法用 Swift 表达。) 但是,如果您的意思是一个 API,您可以在其中调用 service.add(observer: self) 并通过协议一致性以高度通用的方式处理它,不。斯威夫特无法表达。 另外,这正是我们现在可以使用 Combine 来解决的问题。 (我的 Observable 以及后来的实验如 gist.github.com/rnapier/981e86fbf345b049c1df41f63e4a2c6e 都是在 Combine 之前构建的。) 我目前用于生产 ios 11 项目的化身在这里:gist.github.com/rnapier/4a397197a4c698d872301597668d964d 【参考方案1】:

作为一般规则,Swift protocols are not covariant。但是您的问题是一种特殊情况,即使 Swift 允许协议协方差,您的方法也行不通。

在您的示例中,BooksListener 需要执行 Listener 可以执行的所有操作。侦听器可以将任意 Codable 作为其参数传递给listen。这意味着 BooksListener 必须能够接受任意 Codable。考虑以下几点:

struct Books: Codable 

protocol Listener 
    func listen(_ param: Codable)


protocol BooksListener: Listener 
    func listen(_ param: Books)


class MyClass: BooksListener 
    // Illegal, but assuming you had what you're asking for
    func listen(_ param: Books) 


let l: Listener = MyClass()
l.listen("Strings are Codable, and Listener accepts Codable")

这会做什么?这违反了LSP。

您可能想要的是您提到的关联类型(但我稍后会解释为什么您可能不这样做)。使用关联类型,您可以按照我期望的方式定义 Listener。

struct Books: Codable 

protocol Listener 
    associatedtype Parameter: Codable
    func listen(_ param: Parameter)


protocol BooksListener: Listener where Parameter == Books 
    func listen(_ param: Books)


class MyClass: BooksListener 
    func listen(_ param: Books) 

你为什么不想要这个?因为它几乎肯定没有任何意义。我可以用任意的 Listener 做什么?我不能打电话给listen;我不知道参数的类型。没有任何算法可以提供帮助。启用算法就是关联类型的意义所在。

但真正的重点是,“POP”并不意味着“使用大量协议”,也绝对不意味着“使用协议重新创建类继承”。这意味着“从具体类型开始,提取协议以共享算法”。所以在你创建一个单一的协议之前,你需要问,你的程序中存在哪些其他类型的监听器,以及在任意监听器上需要什么算法?如果没有这样的算法,就不应该有协议。

【讨论】:

我已经根据问题本身的内容回答了这个问题。我正在查看您的原始问题,该问题提供了更多背景信息,我将根据该问题在那里写一个答案。

以上是关于协议继承 - 覆盖方法参数的主要内容,如果未能解决你的问题,请参考以下文章

Java 方法重载,方法重写(覆盖),继承等细节注意

覆盖(重写)重载。

重写(覆盖)

比较Java方法的重载与覆盖

php方法重载

php方法重载