这是一个能展示(之前的方式)有多残暴的例子:
class PresentErrorViewController: UIViewController {
var errorViewIsShowing: Bool = false
func presentError(message: String = “Error!", withArrow shouldShowArrow: Bool = false, backgroundColor: UIColor = ColorSalmon, withSize size: CGSize = CGSizeZero, canDismissByTappingAnywhere canDismiss: Bool = true) {
//写下了复杂的,脆弱的代码
}
}
//说一下,有100个class继承了这个class
EveryViewControllerInApp: PresentErrorViewController {}
随着项目的进行事情马上变的明了:并不是每一个UIViewController需要这个error逻辑,或是真的需要这个class所提供的每一个功能。我团队里任何一个人都可以轻易的在这个superclass里改点儿什么,从而影响整个app。这就让代码变得脆弱。还使得代码呈现出了多态。当本应该是由子类决定它自己的行为,这里的superclass却给帮着决定了。下面是在swift 2.0中我们如何用POP来更好的构建这段代码:
protocol ErrorPopoverRenderer {
func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool)
}
extension UIViewController: ErrorPopoverRenderer { //使所有遵从于ErrorPopoverRenderer协议的UIViewController具有一个presentError的默认实现
func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool) {
//加上呈现error视图的默认实现
}
}
class KrakenViewController: UIViewController, ErrorPopoverRenderer { //Drop the God class and make KrakenViewController conform to the new ErrorPopoverRenderer Protocol.
func methodThatHasAnError() {
//…
//抛出error,原因是Kraken海妖今天吃人会感到不适。
presentError(/*blah blah blah 好多参数*/)
}
}
看,这里发生了很炫酷的事情。我们不仅消除了上帝类的存在,还让代码更加的模块化并增强了它的扩展性。通过创建一个 ErrorPopoverRenderer协议,就会让任何遵循了该协议的class具有呈现出一个ErrorView的能力。还不止这些,我们的KrakenViewController class不用必须实现presentError这个函数,因为我们扩展了UIViewController,让它提供了一个默认实现。
唉不过等下!这有个问题!我们每次想要呈现一个ErrorView的时候都必须要去实现每一个参数。这就有点儿让人不爽了,因为我们不能在protocol协议函数声明中为参数提供默认值。
我还挺喜欢这些参数的!更糟的是在让代码更具模块化特征的过程中我们引入了复杂度。还是继续吧,用swift 2.0中新加的一个小妙招来多少的补偿一下:
protocol ErrorPopoverRenderer {
func presentError()
}
extension ErrorPopoverRenderer where Self: UIViewController {
func presentError() {
//在这里加默认实现,并提供ErrorView的默认参数。
}
}
class KrakenViewController: UIViewController, ErrorPopoverRenderer {
func methodThatHasAnError() {
//…
//抛出error,原因是Kraken海妖今天吃人会感到不适。
presentError() //Woohoo! 没有参数了!我们现在有默认实现了!
}
}
好了,现在看起来已经很不错了。我们不仅消除了这些烦人的参数,还用swift 2.0的新特性在protocol的层级上用Self给了presentError一个默认实现。用Self意味着当且仅当协议的遵循者是继承自UIViewController的情况下,这个扩展才会有效。
这就让我们能够把ErrorPopoverRenderer真的当做是一个UIViewController,而甚至不需要对后者做扩展!更棒的是,从现在开始,Swift的运行时是以静态调度而非动态调度去调用presentError()方法。大致的意思就是我们在函数调用点给presentError()方法增强了一点性能。
网友评论