协议扩展与Swift中的类扩展

假设有一个协议Draggable ,通常会被UIView对象所遵循

 protocol Draggable { drag() } 

我们可以在协议扩展中实现drag()作为option 1

 // option 1 extension Draggable where Self: UIView { func drag() { // implementation } } extension UIView: Draggable {} // added after @Rich Tolley's answer 

或者我们可以在UIView扩展中实现drag()作为option 2

 // option 2 extension UIView: Draggable { func drag() { // implementation } } 

这是我的问题:

  • 这两种方法(选项1和选项2)之间是否存在差异?
  • 如果是,那么在我们设计项目或图书馆时有什么区别以及如何选择?

想法会有所帮助。

是的,存在差异:(编辑:或者至少在此q的原始版本中没有添加extension UIView : Draggable {}到选项1的末尾)。

  • 选项1为符合DraggableUIView实例创建默认实现。 你仍然需要在声明中标记UIView你想要符合Draggableclass MyView : Draggable 。 任何符合Draggable但不是UIView子类的东西都需要提供自己的实现。

  • 选项2扩展所有 UIView以使它们符合Draggable 。 除非为这些类编写单独的扩展,否则其他任何东西都不能是可Draggable ,或者它们是手动符合协议的。 无需在类声明中添加Draggable

协议扩展通常是更好的选择。 在这种情况下,这显然是正确的,因为并非所有UIView都可以是Draggable 。 此外,沿着协议扩展路径向下意味着你​​可以创建一个不是UIView子类的Draggable对象,如果有必要的话(不可否认,因为大多数Cocoa控件都是UIView子类 – 尽管不是全部 – UIBarButtonItem不是,奇怪)

如果你遵循选项2,你将在很多情况下向UIView添加不必要的方法,这违反了良好的面向对象设计 – 特别是接口隔离原则(客户端不应该被迫依赖于他们不使用的方法) ) – 这是SOLID原则中的’I’

如果要为多个类实现function,则应使用协议扩展。 在这种情况下,您应该使用extension UIView: Draggable因为Implementation特定于UIView类。

假设您有一个提供位置的协议:

 protocol Location { var location: CGPoint { get set } } 

并且您希望每个实现Location的类都符合Draggable,然后可以使用协议扩展:

 extension Draggable where Self: Location { func drag() { } } 

有关进一步的参考,您应该看看2015 WWDC 中的Swift中面向协议的编程 。