采用协议+扩展 VS 使用实例的区别 class
Difference between adopting protocol+extension VS using instance of a class
我一直在努力掌握面向协议的编程,但我不明白以下两种情况之间的区别...
场景一
我有两个 class 是 UIViewControllers
。这两个 classes 都需要使用一些通用功能,所以我创建了一个协议和一个带有协议默认实现的扩展,然后视图控制器只需要在 class 行中包含协议,它们将自动继承所需的功能。即...
protocol SomeProtocol {
func foo()
}
extension SomeProtocol {
func foo(){
//execute
}
}
class FirstViewController: UIViewController, SomeProtocol {
...
func doSomething(){
foo()
}
}
class SecondViewController: UIViewController, SomeProtocol {
...
func doSomethingElse(){
foo()
}
}
场景二
我有两个 class 是 UIViewControllers
。这两个 classes 都需要使用一些通用功能,因此我创建了一个控制器 class 并且两个 UIViewController
classes 都使用了控制器 class 的一个实例。即...
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()
的 classes 从协议继承,我有什么优势?
What advantage do I get by putting the foo()
function in a protocol and then having the classes that need foo()
inherit from the protocol?
如果您使用协议,您将能够存储通用实例 SomeProtocol
而无需关心它实际是什么:
var myFooable: SomeProtocol
显然,这并不总是有用。如果你不需要存储这样一个通用的实例,使用协议似乎有点过分。
另一方面,使用 Controller
的实例是个坏主意。任何 class 都可以创建一个新的 Controller
对象并在其上调用方法。你在这里试图做的是表达一个 "is able to" 属性,这就是 "conforming to a protocol" 所做的。如果您使用 Controller
的实例,则表示 "has a" 关系。
此外,您为什么还要使用默认实现的协议?如果您不打算在符合 classes 的情况下对协议方法进行不同的实现,请考虑将该方法设为全局函数或将其转换为 "helper methods class".
中的静态方法。
so I create a controller class and both UIViewController classes use an instance of the controller class
这个想法的问题是:你会怎么做,比如说,一个 UITableViewController?你不能,因为你不能把你的控制器 class 变成 UITableViewController 的超级class。
我建议的既不是协议也不是 class 继承。在 class 本身上使用 extension
。您可以扩展 UIViewController,很快,所有 UIViewController 子classes 都具有注入的功能。
当您只需要 class 的特定功能时,面向协议的编程有助于减少子class 更大 class 的冗余。
假设您有 class 具有三个功能的控制器
Class Controller {
func foo() { }
func bar() { }
func fooBar() { }
}
现在您需要另一个只需要 foo()
功能的对象,但是,使用 subclassing Controller,您现在拥有所有 3 个功能。或者您需要复制 func foo()
代码以在两个 class 中都具有功能。
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
}
为了限制这些约束并使您的代码更readable/clear,您创建一个协议 Fooing 并将类型分配给 Fooing。
protocol Fooing {
func foo()
}
class SomeViewController: UIViewController {
let controller: Fooing
}
通过进行此更改,您:
1 - 在您的代码中指明您希望此对象做它能够做的一件事,调用 foo()
函数。
2 - 您不限于控制器 class,您可以使用任何符合 Fooing 的对象,提供更大的灵活性。
3 - 您消除了 Controller subclass 中的任何其他函数在不应该被调用时被调用的机会。
在有限的情况下,它可能不会有太大的不同。但是,您永远不知道将来需求何时会发生变化,最好让自己在需求发生变化时保持最大的灵活性。
当您想将此 foo
功能添加到多个 UIViewController
(或您拥有的)subclasses:
时,有几种方法
带有扩展的协议方法:
问题是,虽然这对于仅 Swift 的代码非常有效,但当您编写必须由 Cocoa 直接调用的代码时,它就不能很好地工作了。
这种方法的优点(如果可以)是您开始享受 WWDC 2015 中概述的优势 Protocol-Oriented Programming in Swift。
组件方法(你有一些 Controller
你的视图控制器可以提供的实例):
当您需要将直接与 Cocoa 集成的共享功能时,这非常有用。例如,这可以在进行自定义视图控制器转换时使用,并且不想在各种视图控制器中重复代码。这种方法可以是 single responsibility principle 的一种体现,可以帮助对抗视图控制器的膨胀。
为了完整起见,还有几个实现重用的选项:
正如 matt 所建议的,您还可以将 foo
实现为某些共享基础 class.
的扩展
当例程不仅对您现有的两个子class而且对所有子class都有意义时,这非常有效。但是,如果这只是那两个特定子classes.
所独有的功能,那么这是不合适的
您还可以将 foo
放入该基数 class 的子 class 中(例如 FooViewController
subclasses UIViewController
), 然后让你之前的两个subclass然后subclass那个新的FooViewController
class.
这解决了基数简单扩展的不加选择的性质 class。
问题在于这不如前两种方法灵活(例如,没有多重继承,一组 Fooable
方法和另一组 Barable
方法)。
最重要的是,正确的方法取决于您要解决的具体问题。您的示例过于笼统,我们无法提供具体建议。
我一直在努力掌握面向协议的编程,但我不明白以下两种情况之间的区别...
场景一
我有两个 class 是 UIViewControllers
。这两个 classes 都需要使用一些通用功能,所以我创建了一个协议和一个带有协议默认实现的扩展,然后视图控制器只需要在 class 行中包含协议,它们将自动继承所需的功能。即...
protocol SomeProtocol {
func foo()
}
extension SomeProtocol {
func foo(){
//execute
}
}
class FirstViewController: UIViewController, SomeProtocol {
...
func doSomething(){
foo()
}
}
class SecondViewController: UIViewController, SomeProtocol {
...
func doSomethingElse(){
foo()
}
}
场景二
我有两个 class 是 UIViewControllers
。这两个 classes 都需要使用一些通用功能,因此我创建了一个控制器 class 并且两个 UIViewController
classes 都使用了控制器 class 的一个实例。即...
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()
的 classes 从协议继承,我有什么优势?
What advantage do I get by putting the
foo()
function in a protocol and then having the classes that needfoo()
inherit from the protocol?
如果您使用协议,您将能够存储通用实例 SomeProtocol
而无需关心它实际是什么:
var myFooable: SomeProtocol
显然,这并不总是有用。如果你不需要存储这样一个通用的实例,使用协议似乎有点过分。
另一方面,使用 Controller
的实例是个坏主意。任何 class 都可以创建一个新的 Controller
对象并在其上调用方法。你在这里试图做的是表达一个 "is able to" 属性,这就是 "conforming to a protocol" 所做的。如果您使用 Controller
的实例,则表示 "has a" 关系。
此外,您为什么还要使用默认实现的协议?如果您不打算在符合 classes 的情况下对协议方法进行不同的实现,请考虑将该方法设为全局函数或将其转换为 "helper methods class".
中的静态方法。so I create a controller class and both UIViewController classes use an instance of the controller class
这个想法的问题是:你会怎么做,比如说,一个 UITableViewController?你不能,因为你不能把你的控制器 class 变成 UITableViewController 的超级class。
我建议的既不是协议也不是 class 继承。在 class 本身上使用 extension
。您可以扩展 UIViewController,很快,所有 UIViewController 子classes 都具有注入的功能。
当您只需要 class 的特定功能时,面向协议的编程有助于减少子class 更大 class 的冗余。
假设您有 class 具有三个功能的控制器
Class Controller {
func foo() { }
func bar() { }
func fooBar() { }
}
现在您需要另一个只需要 foo()
功能的对象,但是,使用 subclassing Controller,您现在拥有所有 3 个功能。或者您需要复制 func foo()
代码以在两个 class 中都具有功能。
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
}
为了限制这些约束并使您的代码更readable/clear,您创建一个协议 Fooing 并将类型分配给 Fooing。
protocol Fooing {
func foo()
}
class SomeViewController: UIViewController {
let controller: Fooing
}
通过进行此更改,您:
1 - 在您的代码中指明您希望此对象做它能够做的一件事,调用 foo()
函数。
2 - 您不限于控制器 class,您可以使用任何符合 Fooing 的对象,提供更大的灵活性。
3 - 您消除了 Controller subclass 中的任何其他函数在不应该被调用时被调用的机会。
在有限的情况下,它可能不会有太大的不同。但是,您永远不知道将来需求何时会发生变化,最好让自己在需求发生变化时保持最大的灵活性。
当您想将此 foo
功能添加到多个 UIViewController
(或您拥有的)subclasses:
带有扩展的协议方法:
问题是,虽然这对于仅 Swift 的代码非常有效,但当您编写必须由 Cocoa 直接调用的代码时,它就不能很好地工作了。
这种方法的优点(如果可以)是您开始享受 WWDC 2015 中概述的优势 Protocol-Oriented Programming in Swift。
组件方法(你有一些
Controller
你的视图控制器可以提供的实例):当您需要将直接与 Cocoa 集成的共享功能时,这非常有用。例如,这可以在进行自定义视图控制器转换时使用,并且不想在各种视图控制器中重复代码。这种方法可以是 single responsibility principle 的一种体现,可以帮助对抗视图控制器的膨胀。
为了完整起见,还有几个实现重用的选项:
正如 matt 所建议的,您还可以将
的扩展foo
实现为某些共享基础 class.当例程不仅对您现有的两个子class而且对所有子class都有意义时,这非常有效。但是,如果这只是那两个特定子classes.
所独有的功能,那么这是不合适的
您还可以将
foo
放入该基数 class 的子 class 中(例如FooViewController
subclassesUIViewController
), 然后让你之前的两个subclass然后subclass那个新的FooViewController
class.这解决了基数简单扩展的不加选择的性质 class。
问题在于这不如前两种方法灵活(例如,没有多重继承,一组
Fooable
方法和另一组Barable
方法)。
最重要的是,正确的方法取决于您要解决的具体问题。您的示例过于笼统,我们无法提供具体建议。