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。
感謝閱讀!🚀