今是昨非

今是昨非

日出江花红胜火,春来江水绿如蓝

Swift代码中的嵌套命名法

Swift 代码中的嵌套命名法#

Swift 支持与其他类型嵌套命名,尽管它还没有专用的命名关键词。下面我们来看看,如何使用类型嵌套来优化我们代码的结构。

大多数 Swift 开发者习惯于用类型在结构上的实际名字累命名。例如:PostTextFormatterOption (一个 Text Formatter 类型的用于 format Posts 的 Option)。这可能是因为我们在 Objective-C & C 中,养成的别无选择的可怕命名习惯,被我们带到了 Swift 里。

下面我们用上面提到的类型作为例子,来看下 Post、PostTextFormatter 以及 PostTextFormatterOption 的实现:

struct Post {
    let id: Int
    let author: User
    let title: String
    let text: String
}

class PostTextFormatter {
    private let options: Set
    
    init(options: Set) {
        self.options = options
    }

    func formatTitle(for post: Post) -> String {
        return post.title.formatted(withOptions: options)
    }

    func formatText(for post: Post) -> String {
        return post.text.formatted(withOptions: options)
    }
}

enum PostTextFormatterOption {
    case highlightNames
    case highlightLinks
}

然后我们再来看一下,如果我们把上面的类型作为 Post 的嵌套类型,会发生什么?

struct Post {
    class TextFormatter {
        enum Option {
            case highlightNames
            case highlightLinks
        }

        private let options: Set

        init(options: Set) {
            self.options = options
        }

        func formatTitle(for post: Post) -> String {
            return post.title.formatted(withOptions: options)
        }

        func formatText(for post: Post) -> String {
            return post.text.formatted(withOptions: options)
        }
    }

    let id: Int
    let author: User
    let title: String
    let text: String
}

上面嵌套类型的一个很大的优点是,我们扫一眼就可以很明白的看到类型之间的的结构和关系。而且我们还减少了初始化代码的冗长,使它更短更易阅读 (options 参数类型从 Set< PostTextFormatterOption> 变为 Set< Option >)。

调用层级也更加简洁明了 —— 所有和 Post 有关的整洁的变为 Post.namespace。一个 post 的文本的格式化看起来如下:

let formatter = Post.TextFormatter(options: [.highlightLinks])
let text = formatter.formatText(for: post)

然而,使用嵌套类型还有一个不容忽视的坏处。代码看起来 “反了”,因为父类型的实际内容被挤到了最下面。我们试着来修复一下这个问题,把嵌套类型的代码从上面移到下面(为了好分辨,还添加一些 MARKs)

struct Post {
    let id: Int
    let author: User
    let title: String
    let text: String

    // MARK: - TextFormatter
    class TextFormatter {
        private let options: Set

        init(options: Set) {
            self.options = options
        }

        func formatTitle(for post: Post) -> String {
            return post.title.formatted(withOptions: options)
        }

        func formatText(for post: Post) -> String {
            return post.text.formatted(withOptions: options)
        }

        // MARK: - Option
        enum Option {
            case highlightNames
            case highlightLinks
        }
    }
}

嵌套类型放上面还是下面纯粹是个人偏好。我比较喜欢把父类型的内容放在上面 ———— 同时还可以享受嵌套类型的便利。

事实上,在 Swift 中还有好几种其他方法可以实现命名、嵌套类型。

使用 extension 实现嵌套类型#

另一个实现嵌套类型的选择就是 extension。这种方法可以在实现和调用时保持层级关系,同时清楚明白的分开每种类型。

看起来如下:

struct Post {
    let id: Int
    let author: User
    let title: String
    let text: String
}

extension Post {
    class TextFormatter {
        private let options: Set

        init(options: Set) {
            self.options = options
        }

        func formatTitle(for post: Post) -> String {
            return post.title.formatted(withOptions: options)
        }

        func formatText(for post: Post) -> String {
            return post.text.formatted(withOptions: options)
        }
    }
}

extension Post.TextFormatter {
    enum Option {
        case highlightNames
        case highlightLinks
    }
}

使用 typealiases#

也可以使用 typealiases。在原始代码里添加 typealiases 来实现类似嵌套类型的代码(实际上并没用嵌套类型)。尽管这种方法在实现上并没有嵌套层级关系,但是却减少了冗长代码 ———— 并且调用看起来也和使用嵌套类型一样。

代码如下:

struct Post {
    typealias TextFormatter = PostTextFormatter

    let id: Int
    let author: User
    let title: String
    let text: String
}

class PostTextFormatter {
    typealias Option = PostTextFormatterOption

    private let options: Set

    init(options: Set) {
        self.options = options
    }

    func formatTitle(for post: Post) -> String {
        return post.title.formatted(withOptions: options)
    }

    func formatText(for post: Post) -> String {
        return post.text.formatted(withOptions: options)
    }
}

enum PostTextFormatterOption {
    case highlightNames
    case highlightLinks
}

最后#

使用嵌套类型有助于写出优雅结构、层级的代码,使多种类型之间的关系更加清楚明了 ———— 不管是在实现上,还是调用上。

然而,由于实现方法的不同,可能会遇到不同的挑战和副作用 ———— 所以我认为根据实际情况选择对应的实现很重要,为了赢得漂亮。

你认为呢?上面那些技术,你倾向于用哪种?或者你还有其他的方法?告诉我你的问题、看法,Twitter@johnsundell

感谢阅读!🚀

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。