什么是 Swift 中的面向协议编程?它带来了什么附加价值?
Posted
技术标签:
【中文标题】什么是 Swift 中的面向协议编程?它带来了什么附加价值?【英文标题】:What is Protocol Oriented Programming in Swift? What added value does it bring? 【发布时间】:2016-05-30 16:40:20 【问题描述】:来自 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 不是相互排斥的。它们是密切相关的设计范式。
POP优于OOP的主要方面是首选composition over inheritance。这样做有几个好处。
在大型继承层次结构中,祖先类倾向于包含大部分(通用)功能,而叶子类只做出很小的贡献。这里的问题是祖先类最终做了很多事情。例如,Car
驾驶、存储货物、安排乘客、播放音乐等。这些功能各不相同,但它们都不可分割地归入Car
类。 Car
的后代,例如Ferrari
、Toyota
、BMW
等,都对该基类进行了最小的修改。
这样做的结果是减少了代码重用。我的BoomBox
也播放音乐,但它不是汽车。无法从 Car
继承音乐播放功能。
相反,Swift 鼓励将这些大型单体类分解为更小的组件的组合。然后可以更轻松地重用这些组件。 Car
和BoomBox
都可以使用MusicPlayer
。
Swift 提供了多种功能来实现这一点,但目前最重要的是协议扩展。它们允许协议的实现与其实现类分开存在,因此许多类可以简单地实现该协议并立即获得其功能。
【讨论】:
1:在 objc 中...每个协议都将应用于其委托。就像你说这个协议的名字是NS*
/ UI*
) 协议倾向于保持它们以前的命名。委托模式仍然存在。
@asma22 仅仅因为它是可能的,并不意味着它是流行的惯例。 Swift 的设计者利用开发新语言的机会重新思考他们想要采用的设计模式。有关协议扩展的更多信息,请阅读developer.apple.com/library/ios/documentation/Swift/Conceptual/…
我建议您通读整个语言指南。它写得很好,并且会比我能更好地回答许多这类问题
@Alexander 我认为上面的 OOP 框架侧重于单继承。使用多重继承,mixin 和功能可以非常小,并导致大小适中的可测试叶子类,而无需始终实现完整的接口。从这个角度来看,POP 和 OOP 似乎可以顺利并驾齐驱。【参考方案2】:
令我惊讶的是,没有一个答案提到 POP 中的值类型。
要了解什么是面向协议编程,您需要了解面向对象编程的缺点。
-
它(Objc)只有一个继承。如果我们有非常复杂的继承层次结构,底层类可能有很多不必要的状态要持有。
它使用作为引用类型的类。引用类型可能会导致代码不安全。例如在修改引用类型时处理它们的集合。
在 swift 中进行面向协议的编程时:
-
它可以符合多种协议。
它不仅可以用于类,还可以用于结构和枚举。
它具有协议扩展,可为符合协议的所有类型提供通用功能。
它更喜欢使用值类型而不是引用类型。看看标准的 swift 库here,你会发现大多数类型都是值类型的结构。但这并不意味着你根本不使用类,在某些情况下,你必须使用类。
因此,面向协议的编程只不过是另一种试图解决 OOP 缺点的编程范式。
【讨论】:
1. OOP 可以通过多重继承来完成,就像 C++ 所做的那样,2. 存在促进 POP 的结构,因此它们缺乏 OOP 是无关紧要的。枚举也可以由类实现。 3. OOP 中可以进行协议扩展/混合。 @AlexanderMomchliov 1. 是的,同意,但是一些流行的语言不能像 c#、Java 等那样具有多重继承。这是苹果的事情,所以我主要区别于 Objc 2。来自 Protocol-Oriented 的视频用 Swift 编程,它清楚地展示了为什么 Apple 更喜欢类型值而不是引用值。所以结构或枚举符合协议是合理的,许多语言不能做到这一点。 3. 协议扩展不仅仅是扩展,您还可以在不使用继承的情况下给出方法的默认实现,以减少重复代码。如果我不正确,请告诉我。【参考方案3】:在 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
)。
您能否投票支持重新提出问题?我相信现在已经消除了歧义【参考方案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】:面向协议的编程(POP)
从 Swift 2.0 开始 类 (OOP) 是引用类型 内存泄漏、存储的数据不正确、在复杂的多线程环境中访问的竞争条件 可以通过在链时继承超类的成员来变大 结构(POP) 是值类型 - 每次在需要时制作新副本 提供多继承 - 继承协议 协议: 定义需要哪些方法、属性和初始化 继承另一个协议 不必使用override关键字来实现协议功能 扩展: 默认值和 协议的默认实现 可以添加额外的成员到 协议【讨论】:
【参考方案6】:面向协议的编程(POP)
协议优先方法
协议作为 OOP 概念的关键点。抽象、继承、多态、封装。 作为 SOLID[About] 基础的协议 协议而不是类层次结构树。很难支持类继承。此外,它还会对性能产生一些影响 类/结构可以实现多个协议(一种多重继承) 组合优于继承。extension MyClass: MyProtocol
默认方法。所有实施者的共享实施
extension MyProtocol
func foo()
//logic
协议继承。一个协议可以扩展另一个协议。协议一的实现者应该实现第一和第二协议的所有内容
protocol ProtocolB: ProtocolA
值类型实现协议(照常引用类型)[About]
【讨论】:
以上是关于什么是 Swift 中的面向协议编程?它带来了什么附加价值?的主要内容,如果未能解决你的问题,请参考以下文章