由于什么原因,您会为Swift中的每个委托使用单独的类扩展?


13

我正在阅读Ray Wenderlich教程,并且注意到作者使用类扩展来保存委托回调,而不是让它们在类本身中进行处理,即:

类扩展内的委托回调:

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

而不是将其包含在类中:

在类内委托回调:

class LogsViewController : UITableViewController, UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

我同时发现这很奇怪也很有趣。他有一个专门用于LogsViewController类的扩展的文件,名为“ LogsViewControllerExtension.swift”,并且每个委托协议都有一个不同的扩展名:UITableViewDataSource,UISplitViewDelegate等,即:

多个类扩展,每个都有自己的文件中的委托回调:

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

为什么?

这样做有什么好处?我可以看到将其分开的可读性更高,但同时又是间接的。是否有OO原则支持或反对这样做?


1
您可以编写许多这样的结构,这些结构从根本上受OO原理支持,但仍会过度设计。
罗伯特·哈维

1
@RobertHarvey正确,但是您是否暗示我在此处显示的示例代码是过度设计的一种形式?委托是iOS开发中的常见模式。另外,无论您是否使用类扩展,都不会更改其中的代码,因此它更像是代码重组而不是重新(过度)设计
morbidhawk 2015年

1
我看到这种将一堆扩展名扔到同一文件中的模式,但我不知道这是从哪里来的。似乎有些人已经在滥用它,只是随意将每一小段代码丢入同一文件的扩展名中。我敢肯定偶尔有这样做的理由,但是我给人的印象是有些程序员只是在不理解为什么的情况下这样做。我一直在寻找使用MARK而不是MARK的优点:-并希望找到一些明确的信息来说明为什么应该以这种方式使用扩展名。
大卫·拉里

Answers:


15

我不知道您为什么说它增加了间接级别。也许您的意思与传统含义有所不同,因为这样做不会产生额外的间接。但是为什么呢?

我这样做是因为它更具模块化。接口所需的所有代码都归于一个地方(实际属性除外)。如果以后我选择制作一个单独的类来实现该协议(从而引入实际的间接级别),则我需要要做的就是将扩展名更改为它自己的类(通过init函数传递所需的属性),并在ViewController上创建一个属性以将该对象实例化为该属性。

我还将所有仅由该协议的功能使用的私有功能放入扩展中。我还没有为扩展创建一个完全独立的文件,但是这样做很清楚那些私有功能仅适用于该协议。

无论如何,人们经常抱怨视图控制器过胖,并且以这种方式破坏视图控制器有助于保持组织得更好,即使这实际上并没有使视图控制器变薄。


我明白您所说的模块化。一旦我了解发生了什么,它看起来就像是一种分离关注点的干净方法。我认为间接性的层次是针对新的眼睛的(并且我偏向于Obj-c方式)。当在基类的其他地方定义了引用代码的子类化时,我感觉到了相同的间接级别,这有点难找。我同意,从组织
上讲

我想这是在Obj-C中的类类别之前完成的。我从不喜欢这些文件,但我认为它们需要单独的文件。从现在开始,您可以在Swift中将扩展名保留在同一文件中,如果我决定像这样分解它们,我可能会这样做
morbidhawk 2015年

2

正如丹尼尔(Daniel)所说的那样,它没有层次。
我同意他的观点,并且我想添加我最近知道的协议扩展的强大功能。

假设您有一个协议didCopyText。您将实现为:

protocol didCopyText {
  var charachtersCount: Int {get}
  func addToClipboardWith(text: String)
}

在Swift中,属性和方法未在Protocol声明中实现,您可能想在每个符合的类中编写实现didCopyText,而使用同一实现的符合该协议的类的增量数量将最终变得一团糟重复的代码。这就是协议扩展派上用场的地方。

protocol didCopyText {
var charachtersCount: Int {
    get {
     // implementation
    }
}
func addToClipboardWith(text: String) {
      // implementation
 }
}

随着协议的属性和方法的实现。现在,任何符合此协议的类都将使用相同的实现。


感谢分享。当我问这个问题时,我没有意识到OO继承的一些缺点,您在这里描述的是一种很好的方式,可以让所有实现该接口的实现类重用相同的函数,而不必被迫从对象继承一切。而且,如果您遵循接口隔离原则,则可以根据需要拆分协议,以确保实现类永远不会从它们不需要的接口中获得属性/方法。
morbidhawk

1

假设您的类支持三种协议,因此您必须添加三组函数。这些功能的唯一目的是支持协议,因此您需要一些文档。

但是,如果您为每个协议添加一个扩展,并且在每个扩展中完全实现了该协议所需的功能,那么可使您的代码更具可读性。

除非这些扩展名确实很大,否则我极有可能不会将它们放在单独的文件中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.