4

我一直在尝试掌握面向协议的编程,但我不明白以下两种情况之间的区别......

方案 1 我有两个类是UIViewControllers. 这两个类都需要使用一些通用功能,所以我创建了一个协议和一个带有协议默认实现的扩展,然后视图控制器只需要在类行中有协议,它们将自动继承所需的功能。IE...

protocol SomeProtocol {
    func foo()
}
extension SomeProtocol {
    func foo(){
        //execute
    }
}

class FirstViewController: UIViewController, SomeProtocol {
    ...

    func doSomething(){
        foo()
    }
}

class SecondViewController: UIViewController, SomeProtocol {
     ...

    func doSomethingElse(){
        foo()
    }
}

场景 2 我有两个类是UIViewControllers. 这两个类都需要使用一些通用功能,因此我创建了一个控制器类,并且这两个UIViewController类都使用了控制器类的一个实例。IE...

class FirstViewController: UIViewController {
    ...
    let controller = Controller()

    func doSomething(){
        controller.foo()
    }
}

class SecondViewController: UIViewController {
    ...
    let controller = Controller()

    func doSomethingElse(){
        controller.foo()
    }
}


class Controller {
    func foo(){
        //execute...
    }
}`

那么区别是什么呢?在我需要使用该foo()功能的任何地方,我都可以获取Controller(). foo()通过将函数放在协议中然后拥有需要的类,我可以获得什么优势foo()从协议继承

4

4 回答 4

4

当您想将此foo功能添加到多个UIViewController(或您拥有的)子类时,有几种方法:

  1. 带有扩展的协议方法:

    问题是,虽然这适用于纯 Swift 代码,但当您编写必须由 Cocoa 直接调用的代码时,它就不能很好地工作了。

    这种方法的优点(如果可以的话)是您开始享受 WWDC 2015 Protocol-Oriented Programming in Swift中概述的优势。

  2. 组件方法(您有一些Controller视图控制器可以出售的实例):

    当您需要将直接与 Cocoa 集成的共享功能时,这非常有用。例如,这可以在进行自定义视图控制器转换并且不想在各种视图控制器中重复代码时使用。这种方法可以体现单一责任原则,并有助于对抗视图控制器膨胀。

为了完整起见,还有几个选项可以实现重用:

  1. 正如马特建议的那样,您还可以foo作为某些共享基类的扩展来实现。

    当例程不仅对您现有的两个子类,而且对所有子类都有意义时,这非常有用。但是,如果这只是这两个特定子类独有的功能,则这是不合适的。

  2. 您还可以放入foo该基类的子类(例如FooViewControllersubclasses UIViewController),然后让您的两个先前的子类然后子类化该新FooViewController类。

    这解决了基类的简单扩展的不分青红皂白的性质。

    问题是这不像前两种方法那样灵活(例如,没有多重继承,一组Fooable方法和另一组Barable方法)。

最重要的是,正确的方法取决于您要解决的具体问题。你的例子太笼统,我们无法提供具体的建议。

于 2017-09-08T18:18:11.413 回答
2

当您只需要该类的特定功能时,面向协议的编程有助于减少对较大类进行子类化的冗余。

假设您有具有三个功能的类控制器

Class Controller {

  func foo() { }

  func bar() { }

  func fooBar() { }
}

现在您需要另一个对象,该对象只需要 的功能foo(),但是,通过子类化 Controller,您现在拥有所有 3 个功能。或者您需要复制func foo()代码以在两个类中都具有功能。

 class SomeViewController: UIViewController {
  /// You only need `func foo()` in this class, but now you have to use an object that carries all the extra functionality you don't need. 
  let controller: ControllerSubclass
}

为了限制这些约束并使您的代码更具可读性/清晰性,您创建一个协议 Fooing 并将类型分配给 Fooing。

 protocol Fooing {
   func foo()
 }

 class SomeViewController: UIViewController {

   let controller: Fooing
 }

通过进行此更改,您:

1 - 在你的代码中表明你希望这个对象做它能够做的一件事,调用foo()函数。

2 - 您不仅限于 Controller 类,您可以使用任何符合 Fooing 的对象,提供更大的灵活性。

3 - 您消除了 Controller 子类中的任何其他函数在不应该被调用时被调用的机会。

在有限的情况下,它可能不会有太大的不同。但是,您永远不知道将来什么时候需求可能会发生变化,并且最好在需求发生变化时给自己留出最大的灵活性。

于 2017-09-08T17:50:37.523 回答
0

foo()将函数放在协议中,然后让需要foo()从协议继承的类有什么好处?

如果您使用协议,您将能够存储泛型的实例SomeProtocol而无需关心它实际上是什么:

var myFooable: SomeProtocol

显然,这并不总是有用的。如果您不需要存储这样的通用实例,使用协议似乎有点过分。

另一方面,使用的实例Controller是一个坏主意。任何类都可以创建一个新Controller对象并在其上调用方法。您在这里尝试做的是表达“能够”属性,这就是“符合协议”所做的。如果您使用 的实例Controller,则表示“具有”关系。

另外,你为什么还要使用带有默认实现的协议呢?如果您不打算在符合类的协议方法中有不同的实现,请考虑将该方法设置为全局函数或将其转换为“辅助方法类”中的静态方法。

于 2017-09-08T17:39:07.047 回答
0

所以我创建了一个控制器类,两个 UIViewController 类都使用了控制器类的一个实例

这个想法的问题是:你将如何为 UITableViewController 做这件事?你不能,因为你不能把你的控制器类变成 UITableViewController 的超类。

我建议既不是协议也不是类继承。extension在类本身上使用 an 。您可以扩展 UIViewController,并且所有 UIViewController 子类都具有注入功能。

于 2017-09-08T17:43:10.197 回答