协议扩展与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为符合
Draggable
的UIView
实例创建默认实现。 你仍然需要在声明中标记UIView
你想要符合Draggable
:class 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中面向协议的编程 。