什么是 Swift 中的面向协议编程?它带来了什么附加价值?

Posted

技术标签:

【中文标题】什么是 Swift 中的面向协议编程?它带来了什么附加价值?【英文标题】:What is Protocol Oriented Programming in Swift? What added value does it bring? 【发布时间】:2016-09-28 13:26:12 【问题描述】:

来自 Apple 自己的网站:“Swift 设计的核心是两个非常强大的想法:面向协议的编程和一流的价值语义。”

谁能详细说明什么是面向协议的编程,它带来了什么附加值?

我已经阅读了this 并观看了 Swift 中的面向协议编程video,但是来自 Objective-C 的背景仍然没有理解它。我恳请非常简单的英文答案以及代码 sn-ps 和有关它与 Objective-C 有何不同的技术细节。

一个我的困惑是使用<tableViewDelegate, CustomDelegate> 难道我们不能也符合Objective-C 中的多个协议吗?那么 Swift 又是如何新的呢?


编辑:见Protocol-Oriented Views 视频。我发现这个视频更基础,更容易掌握有意义的用例。 WWDC 视频本身有点高级,需要更多的广度。此外,这里的答案有些抽象。

【问题讨论】:

它(几乎)与 Java 中的 interfaced based programming 相同。 观看Crusty @vadian 这与他在问题中引用的视频完全相同。但是,该视频对这个主题的介绍是如此容易理解,以至于我不清楚你如何观看它并且有这些问题。 @asma22 “协议”的含义没有区别。 Swift 只是为协议添加了新特性(协议扩展、协议泛型等),但它与 ObjC 中的“协议”的含义基本相同。 IMO 这个问题和答案非常有用。当伟大的问题因为被认为不适合 SO 而被关闭时,这是一种耻辱。 【参考方案1】:

面向协议的编程(POP)

协议优先方法

协议作为 OOP 概念的关键点。抽象、继承、多态、封装。 作为 SOLID[About] 基础的协议 协议而不是类层次结构树。很难支持类继承。此外,它还会对性能产生一些影响 类/结构可以实现多个协议(一种多重继承) 组合优于继承。
extension MyClass: MyProtocol 

默认方法。所有实施者的共享实施
extension MyProtocol 
    func foo() 
        //logic
    

协议继承。一个协议可以扩展另一个协议。协议一的实现者应该实现第一和第二协议的所有内容
protocol ProtocolB: ProtocolA 

值类型实现协议(照常引用类型)[About]

【讨论】:

【参考方案2】:

面向协议的编程(POP)

从 Swift 2.0 开始 类 (OOP) 是引用类型 内存泄漏、存储的数据不正确、在复杂的多线程环境中访问的竞争条件 可以通过在链时继承超类的成员来变大 结构(POP) 是值类型 - 每次在需要时制作新副本 提供多重继承 - 继承协议 协议: 定义需要哪些方法、属性和初始化 继承另一个协议 不必使用override关键字来实现协议功能 扩展: 默认值和 协议的默认实现 可以添加额外的成员到 协议

【讨论】:

【参考方案3】:

令我惊讶的是,没有一个答案提到 POP 中的值类型。

要了解什么是面向协议编程,您需要了解面向对象编程的缺点。

    它(Objc)只有一个继承。如果我们有非常复杂的继承层次结构,底层类可能有很多不必要的状态要持有。 它使用作为引用类型的类。引用类型可能会导致代码不安全。例如在修改引用类型时处理它们的集合。

在 swift 中进行面向协议的编程时:

    它可以符合多种协议。 它不仅可以用于类,还可以用于结构枚举。 它具有协议扩展,可为符合协议的所有类型提供通用功能。 它更喜欢使用值类型而不是引用类型。看看标准的 swift 库here,你会发现大多数类型都是值类型的结构。但这并不意味着你根本不使用类,在某些情况下,你必须使用类。

因此,面向协议的编程只不过是另一种试图解决 OOP 缺点的编程范式。

【讨论】:

1. OOP 可以通过多重继承来完成,就像 C++ 所做的那样,2. 存在促进 POP 的结构,因此它们缺乏 OOP 是无关紧要的。枚举也可以由类实现。 3. OOP 中可以进行协议扩展/混合。 @AlexanderMomchliov 1. 是的,同意,但是一些流行的语言不能像 c#、Java 等那样具有多重继承。这是 Apple 的东西,所以我主要区别于 Objc 2。来自 Protocol-Oriented 的视频用 Swift 编程,它清楚地展示了为什么 Apple 更喜欢类型值而不是引用值。所以结构或枚举符合协议是合理的,许多语言不能做到这一点。 3. 协议扩展不仅仅是扩展,您还可以在不使用继承的情况下给出方法的默认实现,以减少重复代码。如果我不正确,请告诉我。【参考方案4】:

添加到上面的答案

Protocol 是一个接口,其中声明了方法和属性的签名,并且枚举的任何子类/结构/枚举都必须遵守约定,这意味着它们必须实现声明的所有方法和属性在超类协议中。

使用协议的原因

类提供单一继承,而结构不支持继承。因此引入了协议。

扩展 协议内部声明的方法可以在扩展内部实现,以避免在多个具有相同方法实现的类/结构中继承协议时代码的冗余。我们可以通过简单地声明 struct/enums 的对象来调用该方法。即使我们可以将扩展限制为一个类列表,只有受限类才能使用扩展内部实现的方法,而其他类必须实现自己类内部的方法。

示例

protocol validator

    var id : String get 
    func capitialise()-> (String)



extension validator where Self : test
    func capitialise() -> String
        return id.capitalized
    


class test : validator 

    var id: String

    init(name:String) 
        id = name
    


let t = test(name: "Ankit")
t.capitialise()

什么时候使用 在OOP中假设我们有一个车辆基类,它被飞机、自行车、汽车等继承。这里break,加速可能是三个子类的通用方法,但不是flyable方法的飞机。因此,如果我们也在 OOP 中声明 flyable 方法,那么 bike 和 car 子类也有继承 flyable 方法,这对这些类没有用处。因此,在 POP 中,我们可以声明两种协议,一种用于可飞行物体,另一种用于中断和加速方法。并且flyable协议可以限制为只能由飞机使用

【讨论】:

【参考方案5】:

在 Objective C 中,协议与大多数语言中的接口相同。所以在Objective C协议中的使用仅限于SOLID原则“依赖抽象。不要依赖具体。

在 Swift 中,协议得到了如此严重的改进,因为它们仍然可以用作接口,实际上它们更接近于类(如 C++ 中的Abstract classes)

在 Objective C 中,在类之间共享功能的唯一方法是继承。你可以继承唯一的 one 父类。在 Swift 中,您还可以采用任意数量的协议。由于 Swift 中的协议可以有默认方法实现,它们为我们提供了一个功能齐全的Multiple inheritance。更大的灵活性,更好的代码重用 - 太棒了!

结论:

面向协议的编程OOP基本相同,但它更加关注功能共享,不仅通过继承而且通过协议采用 (Composition over inheritance)。

值得一提的是,C++ 中的抽象类与 Swift 中的协议非常相似,但没有人说 C++ 支持某种特定类型的 OOP。所以在general中,如果我们谈论编程范式,POP 是 OOP 的一种版本。 For Swift POP 是 OOP 的改进版本。

【讨论】:

我理解您所说的部分内容。并感谢***链接。这很棒。所以你是说协议这个词在两​​种语言中没有相似的含义?对于Objective-C,我们不是也可以让我们的viewcontroller类符合多种协议吗?扩展其功能?我不明白其中的区别。请您详细说明一下 我认为您已经掌握了主要思想。在 Objective C 中,协议与大多数语言中的interface 相同。在 Swift 中,协议得到了如此严重的改进,因为它们仍然可以用作接口,实际上它们更接近于类(如 C++ 中的Abstract classes)。 您能否投票支持重新提出问题?我相信现在已经消除了歧义【参考方案6】:

前言:POP 和 OOP 不是相互排斥的。它们是密切相关的设计范式。

POP优于OOP的主要方面是首选composition over inheritance。这样做有几个好处。

在大型继承层次结构中,祖先类倾向于包含大部分(通用)功能,而叶子类只做出很小的贡献。这里的问题是祖先类最终会做很多事情。例如,Car 驾驶、存储货物、安排乘客、播放音乐等。这些功能各不相同,但它们都不可分割地归入Car 类。 Car 的后代,例如FerrariToyotaBMW 等,都对该基类进行了最小的修改。

这样做的结果是减少了代码重用。我的BoomBox 也播放音乐,但它不是汽车。无法从Car 继承音乐播放功能。

相反,Swift 鼓励将这些大型单体类分解为更小的组件的组合。然后可以更轻松地重用这些组件。 CarBoomBox 都可以使用MusicPlayer

Swift 提供了多种功能来实现这一点,但迄今为止最重要的是协议扩展。它们允许协议的实现与其实现类分开存在,因此许多类可以简单地实现该协议并立即获得其功能。

【讨论】:

1:在 objc 中...每个协议都将应用于其委托。就像你说这个协议的名字是 某些核心类型的命名已简单更改。 Foundation Frameworks 的 (NS* / UI*) 协议倾向于保持以前的命名方式。委托模式仍然存在。 @asma22 仅仅因为它是可能的,并不意味着它是流行的约定。 Swift 的设计师们利用开发一种新语言的机会重新思考了他们想要采用的设计模式。有关协议扩展的更多信息,请阅读developer.apple.com/library/ios/documentation/Swift/Conceptual/… 我建议您通读整个语言指南。它写得很好,会比我能更好地回答许多这类问题 @Alexander 我认为上面的 OOP 框架侧重于单继承。使用多重继承,mixin 和功能可以非常小,并导致大小适中的可测试叶子类,而无需始终实现完整的接口。从这个角度来看,POP 和 OOP 似乎可以顺利并驾齐驱。

以上是关于什么是 Swift 中的面向协议编程?它带来了什么附加价值?的主要内容,如果未能解决你的问题,请参考以下文章

Swift 中的面向协议编程:是否优于面向对象编程?

Swift中面向协议的编程

为什么swift是面向协议的编程--对面向对象机制的改进

WWDC Swift 会话中面向协议的编程

swift面向协议编程(POP)的一些Tips

swift iOS中的面向协议编程