方法嵌套

方法终于成为了一等公民,也就是说,我们可以将方法当作变量或者参数来使用了。更进一步地,我们甚至可以在一个方法中定义新的方法,这给代码结构层次和访问级别的控制带来了新的选择。
想想看有多少次我们因为一个方法主体内容过长,而不得不将它重构为好几个小的功能块的方法,然后在原来的主体方法中去调用这些小方法。这些具体负责一个个小功能块的方法也许一辈子就被调用这么一次,但是却不得不存在于整个类型的作用域中。虽然我们会将它们标记为私有方法,但是事实上它们所承担的任务往往和这个类型没有直接关系,而只是会在这个类型中的某个方法中被用到。更甚至这些小方法也可能有些复杂,我们还想进一步将它们分成更小的模块,我们很可能也只有将它们放到和其他方法平级的地方。这样一来,本来应该是进深的结构,却被整个展平了,导致之后在对代码的理解和维护上都很成问题。在 Swift 中,我们对于这种情况有了很好的应对,我们可以在方法中定义其他方法,也就是说让方法嵌套起来。
举个例子,我们在写一个网络请求的类 Request
时,可能面临着将请求的参数编码到 url 里的任务。因为输入的参数可能包括单个的值,字典,或者是数组,因此为了结构漂亮和保持方法短小,我们可能将情况分开,写出这样的代码:

    func appendQuery(url: String,
                     key: String,
                     value: AnyObject) -> String {
        if let dictionary = value as? [String: AnyObject] {
            return appendQueryDictionary(url: url, key: key, value: dictionary)
        } else if let array = value as? [AnyObject] {
            return appendQueryArray(url: url, key: key, value: array)
        } else {
            return appendQuerySingle(url: url, key: key, value: value)
        }
    }
    
    func appendQueryDictionary(url: String,
                               key: String,
                               value: [String: AnyObject]) -> String {
        //...
        return ""
    }
    
    func appendQueryArray(url: String,
                          key: String,
                          value: [AnyObject]) -> String {
        //...
        return ""
    }
    
    func appendQuerySingle(url: String,
                           key: String,
                           value: AnyObject) -> String {
        //...
        return ""
    }

事实上后三个方法都只会在第一个方法中被调用,它们其实和 Request
没有直接的关系,所以将它们放到 appendQuery
中去会是一个更好的组织形式:

    func appendQuery(url: String,
                     key: String,
                     value: AnyObject) -> String {
        
        func appendQueryDictionary(url: String,
                                   key: String,
                                   value: [String: AnyObject]) -> String {
            //...
            return ""
        }
        
        func appendQueryArray(url: String,
                              key: String,
                              value: [AnyObject]) -> String {
            //...
            return ""
        }
        
        func appendQuerySingle(url: String,
                               key: String,
                               value: AnyObject) -> String {
            //...
            return ""
        }
        
        if let dictionary = value as? [String: AnyObject] {
            return appendQueryDictionary(url: url, key: key, value: dictionary)
        } else if let array = value as? [AnyObject] {
            return appendQueryArray(url: url, key: key, value: array)
        } else {
            return appendQuerySingle(url: url, key: key, value: value)
        }
    }

另一个重要的考虑是虽然 Swift 提供了 public,internal 和 private
三种访问权限,但是有些方法我们完全不希望在其他地方被直接使用。最常见的例子就是在方法的模板中:我们一方面希望灵活地提供一个模板来让使用者可以通过模板定制他们想要的方法,但另一方面又不希望暴露太多实现细节,或者甚至是让使用者可以直接调用到模板。一个最简单的例子就是类似这样的代码:

    func makeIncrementor(addNumber: Int) -> ((inout Int) -> Void) {
        func incrementor(variable: inout Int) -> Void {
            variable += addNumber;
        }
        return incrementor;
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,881评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,113评论 25 708
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,200评论 4 61
  • 什么是活着, 明明活着, 却还如同死去。 什么是死亡, 明明心向神往, ...
    古风长歌阅读 164评论 0 2
  • 有时候,默契真Tmd的也不是好事。比如就像现在你不说话我也不说话,就这样一步一步走到学校。 站在门口看着婉儿有条不...
    韦小天阅读 261评论 0 1