何时在Swift中使用协议?

11

今天我提出了一个问题,因为今天我有点迷茫。这个问题与Swift和协议有关,更多地涉及到面向协议的编程(POP)。

我读过相关文章,甚至看过一本书,但我仍然感到困惑。每个人似乎都说协议是一个很好的工具等等,但我并不真正理解它的威力。

我有一个问题,因为我正在编写一个名为Volume的类,它是表示一个音量对象的类。让我们说

struct Volume {
  var value: Float = 1
  var isLogScale: Bool = false
  var maxLogVolume: Float = 6.0 // value in dB
  var maxLinearVolume: Float = 1.0
  let dynamicRange: Float = 50.0


  func convertLinearToLog() -> Float {
    // Do some maths
  }

  func otherFunction() {
    print("Hello, I'm the most useless function in the world.")
  }
}

这是一个典型的课程,没有什么特别之处。

但是...我是否应该更好地使用像这样的协议:

protocol VolumeProtocol {
  var value: Float {get set}
  var isLogScale: Bool {get set}
  var maxLogVolume: Float {get set}
  var maxLinearVolume: Float {get set}
  let dynamicRange: Float {get}

  func convertLinearToLog() -> Float
  func otherFunction()
}

然后重新实现所有内容,例如

struct MyVolumeClass: VolumeProtocol {
// Same thing as before
}
我不太能回答这个问题,如果你能帮我理解什么时候需要使用"protocol",什么时候不需要,我会感激不尽。

1
你应该使用结构体而不是类。顺便提一下,值得一看 https://developer.apple.com/videos/play/wwdc2015/408/ - Leo Dabus
1
@LeoDabus,你说得完全正确。很抱歉我在类/结构体方面犯了一个错误。实际上,这个案例完全是一个结构体。我已经编辑了我的问题。感谢提供的链接。 - DEADBEEF
2
通常使用协议的一个可能场景是当您想要抽象出一些多个类的共同方法/属性,但由于某种原因(例如,您的类需要继承自另一个类),您不想使用继承。对于您当前的实现来说,创建一个VolumeProtocol没有意义,因为我不认为您会有多个不同的类符合这个协议。 - Dávid Pásztor
@DávidPásztor感谢您的解释,这就是为什么我觉得我的情况不好的原因。实际上,协议可以看作是一个大的超类,我们将其切成小的专注于某个方面的类。实际上,在我的情况下,它可能是遵循先前协议的procotols“volume”、“audioFormat”和类“singleAudioPlayer”、“multipleAudioPlayer”。对我来说,这仍然不是自然的,因为仅使用声明编写“protocol”似乎对我来说毫无用处(我只使用协议进行委托模式),但它有助于代码的维护。 - DEADBEEF
1
@DEADBEEF 你也可以在协议中定义函数的默认实现,这样协议就不仅仅是声明了。 - Dávid Pásztor
1个回答

11

协议有多个用途,但可以这样理解:

  • 对于类,协议提供了轻量级的继承层次结构,与类层次结构分开。给定一个类Animal及其子类Cat、Dog、Bird和Insect,如何指定只有Bird和Insect共享fly方法?

  • 对于结构体,协议提供了本来完全缺少的继承层次结构!结构体没有超级结构体。因此,对于一个结构体Bird和一个结构体Insect,如何指定它们共享fly方法?

现在,你可能会回答Bird和Insect恰好具有fly方法,这就是故事的结束。但是当您需要讨论“所有具有fly方法的类型集”时,这并不够用。而且当您希望编译器能够将fly方法发送到具有该方法的对象时,确实需要讨论该集合。

解决方案是使用协议:

protocol Flier {
    func fly()
}

现在 Flier 是一个 类型。符合 Flier 标准的任何类型的实例都可以用作期望 Flier 的地方,编译器会允许您告诉任何 Flier fly,因此问题得到解决:

var myFlier : Flier = Bird() // if Bird conforms to Flier
myFlier.fly() // legal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接