我一直在努力掌握面向协议的编程,但我不明白以下两种情况之间的区别......
场景1
我有两个类UIViewControllers
。这两个类都需要使用一些常用功能,因此我使用协议的默认实现创建协议和扩展,然后视图控制器只需要在类行中具有协议,它们将自动继承所需的功能。即...
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
类都使用了控制器类的实例。即...
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()
的类继承协议,我会获得什么好处?
答案 0 :(得分:3)
如果要将此foo
功能添加到多个UIViewController
(或您拥有的)子类,有几种方法:
带扩展名的协议方法:
问题在于,虽然这对于仅使用Swift的代码很有效,但是当你编写必须由Cocoa直接调用的代码时,它不能很好地工作。
这种方法的优点(如果可以的话)是您开始享受WWDC 2015 Protocol-Oriented Programming in Swift中概述的优势。
组件方法(您的视图控制器可以提供的Controller
实例):
当您需要直接与Cocoa集成的共享功能时,这非常棒。例如,这可以在执行自定义视图控制器转换时使用,并且不希望在各种视图控制器中重复代码。这种方法可以是single responsibility principle的一种表现形式,可以帮助对抗视图控制器臃肿。
为了完整起见,还有一些选项可以实现重用:
正如matt建议的那样,您还可以将foo
实现为某些共享基类的扩展。
当例程不仅对你的两个现有子类有意义,而且对所有子类都有意义时,这很有用。但如果这只是那两个特定子类的独特功能,那么这是不合适的。
您也可以将foo
放入该基类的子类(例如FooViewController
子类UIViewController
),然后让您的前两个子类继承新FooViewController
1}} class。
这解决了基类的简单扩展的不加区分的性质。
问题在于,这不像前两种方法那样灵活(例如,没有多重继承,一组Fooable
方法和另一组Barable
方法)。
最重要的是,正确的方法取决于您尝试解决的具体问题。您的例子太过通用,我们无法提供具体的建议。
答案 1 :(得分:2)
假设你有三个函数的类控制器
Class Controller {
func foo() { }
func bar() { }
func fooBar() { }
}
现在您需要另一个只需要foo()
功能的对象,但是,通过子类控制器,您现在拥有所有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子类中的任何其他函数时,你将删除它。
在有限的情况下,它可能没有多大区别。但是,您永远不会知道将来需求可能会发生变化,并且最好在变更时为自己留出最大的灵活性。
答案 2 :(得分:1)
所以我创建了一个控制器类,两个UIViewController类都使用控制器类的实例
这个想法的问题是:你会怎么做,比如UITableViewController?你不能,因为你不能把你的控制器类变成UITableViewController的超类。
我建议的不是协议也不是类继承。在类本身上使用extension
。您可以扩展UIViewController,并且presto,所有UIViewController子类都具有注入的功能。
答案 3 :(得分:0)
通过将
foo()
函数放在协议中然后让需要foo()
的类继承协议,我可以获得什么好处?
如果您使用协议,您将能够存储通用SomeProtocol
的实例,而无需关心其实际内容:
var myFooable: SomeProtocol
显然,这并不总是有用的。如果您不需要存储这样的通用实例,使用协议似乎有点过分。
另一方面,使用Controller
的实例是一个坏主意。任何类都可以创建一个新的Controller
对象并在其上调用方法。你在这里要做的是表达一个“能够”属性,这是“符合协议”的。如果您使用Controller
的实例,则表示“有”关系。
此外,为什么要使用默认实现的协议?如果您不打算在符合类中使用协议方法的不同实现,请考虑将该方法设置为全局函数或将其转换为“辅助方法类”中的静态方法。