美文网首页
协议的实用性

协议的实用性

作者: George2016 | 来源:发表于2017-06-05 12:10 被阅读7次

    这是一个能展示(之前的方式)有多残暴的例子:

    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()方法增强了一点性能。

    原文转载

    相关文章

      网友评论

          本文标题:协议的实用性

          本文链接:https://www.haomeiwen.com/subject/ufeifxtx.html