为什么协议在swift中比class好?

bea*_*one 10 protocols class ios swift

通过观看Apple提供的视频教程,似乎swift是面向协议的编程语言,苹果鼓励程序员使用协议而不是类.但从我个人的角度来看,我认为协议没有明显的优势.class可以符合协议,但它们也可以从超类继承.我们可以为协议添加扩展,但我们也可以为类添加扩展.我们可以在符合协议的类中实现函数,但我们也可以在子类中覆盖func.我仍然感到困惑,为什么我们需要使用协议而不是类.当我们应该使用协议而不是类?

Dav*_*rry 13

类和协议是正交概念.协议跨越类树并且使用不同的祖先连接一个或多个类.

也许更简单地说:

  • "class"定义了一个对象是什么.
  • "protocol"定义了对象具有的行为.

所以你有一个班车:

class Car {
    var bodyStyle : String
}
Run Code Online (Sandbox Code Playgroud)

和一个颜色:

class Color {
    var red : Int
    var green : Int
    var blue : Int
}
Run Code Online (Sandbox Code Playgroud)

现在,或多或少显然颜色和汽车完全不相关,但是,假设我希望能够轻松地将其中一个转换为字符串,所以我可以调试:

print(Car(...))
Run Code Online (Sandbox Code Playgroud)

要么

print(Color(...))
Run Code Online (Sandbox Code Playgroud)

为了这个目的,Swift语言定义了协议,CustomStringConvertible因此我们可以声明可以使用该协议打印Car:

extension Car : CustomStringConvertible {
    var description : String { get { return "Car: \(bodyStyle)" } }
}
Run Code Online (Sandbox Code Playgroud)

还有一个颜色:

extension Color : CustomStringConvertible {
    var description : String { get { return "Color: \(red) \(green) \(blue)" } }
}
Run Code Online (Sandbox Code Playgroud)

所以在我需要为每个类创建一个打印方法之前,现在我只需要一个看起来像这样的打印方法:

func print(data:CustomStringConvertible) {
    let string = data.description
    ... bunch of code to actually print the line
}
Run Code Online (Sandbox Code Playgroud)

这是可能的,因为声明一个类实现一个协议是一个承诺,我可以使用协议中的方法,知道它们已经实现并且(可能)做了预期的事情.


小智 9

让我们来看一个下载示例.

您有一个基类FileDownloadModel,并有3个子类AudioFileDownloadModel,VideoFileDownloadModel和ImageDownloadModel.

你有一个DownloadManager,它接受FileDownloadModel输入并使用这个模型的urlToDownload属性来下载文件.

后来下了线,你被告知还有一个模式来,但它的类型UserDownloadModel这是一个子类用户,而不是FileDownloadModel.

现在看,很难处理这种情况,你必须更改大量代码以合并下载方法.

面向协议的编程如何帮助您:

  1. 创建名为DownloadingFileProtocol的协议,并添加下载文件所需的方法和属性.例如.urlToDownload,pathToSave,extension等.
  2. FileDownloadModelUserDownloadModel中实现相同的协议.这样做的好处是您不必在UserDownloadModel中更改大量代码.您只需实现DownloadingFileProtocol中的方法.
  3. 如果新实体再次下线,您将不会更改任何代码.相反,您只需实现协议方法.
  4. 现在,您的DownloadManager可以将 DownloadingFileProtocol作为输入而不是特定模型.同样,您现在可以通过采用此协议使任何模型"可下载".