Swift代码中的嵌套命名法
Swift支持与其他类型嵌套命名,尽管它还没有专用的命名关键词。下面我们来看看,如何使用类型嵌套来优化我们代码的结构。
大多数Swift开发者习惯于用类型在结构上的实际名字累命名。例如:PostTextFormatterOption(一个Text Formatter类型的用于format Posts的Option)。这可能是因为我们在Objective-C & C中,养成的别无选择的可怕命名习惯,被我们带到了Swift里。
下面我们用上面提到的类型作为例子,来看下Post、PostTextFormatter以及PostTextFormatterOption的实现:
代码语言:javascript复制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的嵌套类型,会发生什么?
代码语言:javascript复制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的文本的格式化看起来如下:
代码语言:javascript复制let formatter = Post.TextFormatter(options: [.highlightLinks])
let text = formatter.formatText(for: post)
然而,使用嵌套类型还有一个不容忽视的坏处。代码看起来“反了”,因为父类型的实际内容被挤到了最下面。我们试着来修复一下这个问题,把嵌套类型的代码从上面移到下面(为了好分辨,还添加一些MARKs)
代码语言:javascript复制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。这种方法可以在实现和调用时保持层级关系,同时清楚明白的分开每种类型。
看起来如下:
代码语言:javascript复制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来实现类似嵌套类型的代码(实际上并没用嵌套类型)。尽管这种方法在实现上并没有嵌套层级关系,但是却减少了冗长代码————并且调用看起来也和使用嵌套类型一样。
代码如下:
代码语言:javascript复制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。
感谢阅读!?