通过观看Apple提供的视频教程,似乎swift是面向协议的编程语言,苹果鼓励程序员使用协议而不是类。 但从我个人的角度来看,我认为协议没有明显的优势。 class可以符合协议,但它们也可以从超类继承。我们可以为协议添加扩展,但我们也可以为类添加扩展。我们可以在符合协议的类中实现函数,但我们也可以在子类中覆盖func。 我仍然感到困惑,为什么我们需要使用协议而不是类。当我们应该使用协议而不是类?
答案 0 :(得分:13)
类和协议是正交概念。协议跨越类树,并使用不同的祖先加入一个或多个类。
或许更简单地说:
所以你有一个班车:
class Car {
var bodyStyle : String
}
和一个颜色:
class Color {
var red : Int
var green : Int
var blue : Int
}
现在,或多或少显然颜色和汽车是完全无关的,但是,我想我希望能够轻松地将其中任何一个转换为字符串,所以我可以调试:
print(Car(...))
或
print(Color(...))
正是出于这个目的,Swift语言定义了协议CustomStringConvertible
,因此我们可以声明可以使用该协议打印Car:
extension Car : CustomStringConvertible {
var description : String { get { return "Car: \(bodyStyle)" } }
}
和一个颜色:
extension Color : CustomStringConvertible {
var description : String { get { return "Color: \(red) \(green) \(blue)" } }
}
所以,在我需要为每个类创建一个打印方法之前,现在我只需要一个看起来像这样的打印方法:
func print(data:CustomStringConvertible) {
let string = data.description
... bunch of code to actually print the line
}
这是可能的,因为声明一个类实现协议是一种承诺,我可以使用协议中的方法,知道它们已经实现并且(可能)做了预期的事情。
答案 1 :(得分:8)
让我们下载一个例子。
您有一个基类 FileDownloadModel ,并有3个子类 AudioFileDownloadModel,VideoFileDownloadModel和ImageDownloadModel 。
您有一个 DownloadManager ,它接受 FileDownloadModel 输入,并使用此模型的 urlToDownload 属性下载文件。
稍后您会被告知还有一个模型即将推出,但它的类型为 UserDownloadModel ,它是用户<的子类 / strong>,而不是 FileDownloadModel 。
现在看,很难处理这种情况,你必须更改大量代码以合并下载方法。
面向协议的编程如何帮助您:
答案 2 :(得分:3)
很大程度上,它是类型的层次结构。假设您有一个表示GlowingRedCube
的对象,但您希望在许多关心的通用代码中使用该类型:
Cube
延伸Shape
Red
延伸Colorful
Glowing
延伸Illuminated
你遇到了麻烦。你可以选择一个基类并添加特化:GlowingRedCube
extends GlowingCube
extends Shape
,但是你会得到一组非常广泛的类,以及一组不灵活的东西(如果你想要的话)制作SoftRedCube
,但保留您为现有红色立方体类型定义的任何方法?)
你可能只有Cube
并且具有属性的照明和形状,但是你没有得到好的编译器类型检查:如果你有一个Room.lightUp()
方法并且必须通过它Cube
,然后您需要检查该类型是否包含任何照明!如果你只能传递Illuminated
,那么编译器会在你尝试时立即阻止你。
协议允许您将其分开:GlowingRedCube
可以实现Illuminated
协议,Colorful
协议和Shape
协议。由于协议扩展,您可以包含默认的功能实现,因此您不必选择要将其附加到的层次结构级别。
struct GlowingRedCube: Shape, Colorful, Illuminated {
// ..
}
实际上,协议允许您将行为附加到对象,而不管该对象做了什么。这正是他们用于代理和数据源协议之类的原因:即使您主要将这些内容附加到ViewController
,基础对象也不相关,所以你可以灵活地了解你的实施方式。
在Swift中使用协议远不仅仅是基础知识:它们非常强大,因为它们可以附加到许多不同的代码结构:类,结构和枚举。这允许您首先真正接近编程协议。来自WWDC last year的这种方法有一个很棒的视频,但是首先要花一些时间自己尝试一些不同的对象结构以了解问题。
答案 3 :(得分:1)
使用协议,一个类/结构可以用作不同的东西。例如,String
结构符合soooo许多协议!
Comparable
CustomDebugStringConvertible
Equatable
ExtendedGraphemeClusterLiteralConvertible
Hashable
MirrorPathType
OutputStreamType
Streamable
StringInterpolationConvertible
StringLiteralConvertible
UnicodeScalarLiteralConvertible
这意味着String
可以用作11种不同的东西!当某个方法需要上述任何一个协议作为参数时,您可以传入一个字符串。
“但我可以创建一个具有协议所有方法的神类!”你争辩说。请记住,您只能从Swift中的一个类继承,并且多重继承使用起来非常危险,因为它可能会使您的代码变得非常复杂。
此外,使用协议,您可以定义类的自定义行为。 String
的{{1}}方法与hashcode
方法不同。但它们都与此功能兼容:
Int
这是协议的真正奇迹。
最后但并非最不重要的是,协议有意义。协议代表“是一种”或“可以用作”的关系。当X可以用作Y时,X符合协议Y是对的吗,对吗?