做者:Natasha The Robot,原文連接,原文日期:2016-05-28
譯者:Channe;校對:Cee;定稿:千葉知風git
我最近在讀《重構與模式》 。昨天(譯註:原文日期的昨天),在我寫描述了一個擁有多個參數的對象的《建立方法》時,想到了@modocache關於iOS API 設計中的 Swift 模式超棒的演講,尤爲是關於參數對象部分。我第一次看的時候獲益匪淺,所以我但願記錄下來。github
假設你在寫一個 BananaUIKit 庫,包含了一個簡單的 BananaAlertView:swift
最開始的代碼可能想這樣:設計模式
public class BananaAlertView { public static func show( withTitle title: String, message: String, dismissButtonText: String) { // 具體實現 } }
這個實現很好,直到一位使用這個框架的用戶請求可以將 BananaAlertView 的顏色由棕色換爲黃色...閉包
爲了確保更改這個框架不影響其餘用戶,咱們使用 Swift 的默認參數:框架
public class BananaAlertView { public static func show( withTitle title: String, message: String, dismissButtonText: String, // 新的無痛更改 tintColor: UIColor = .yellowColor()) { // 具體實現 } }
只要咱們給方法添加參數,它就能很好的工做。可是若是咱們想要將參數添加到別的東西就不行了,好比 BananaAlertView 上一個按鈕被點擊後的閉包:spa
public class BananaAlertView { // 按鈕被點擊後的動做 public typealias ButtonCallback = (buttonIndex: Int) -> Void public static func show( withTitle title: String, message: String, dismissButtonText: String, // 回調參數 dismissButtonCallback: ButtonCallback) { // 具體實現 } } // 用法 BananaAlertView.show( withTitle: "This is Bananas", message: "Someone has been monkeying around ?", dismissButtonText: "Banana", dismissButtonCallback: { buttonIndex in // 具體實現 })
可是假如咱們須要改變閉包的參數呢?假如客戶端一樣須要按鈕的文本呢?翻譯
解決方式就是爲 ButtonCallback 添加一個按鈕文本的參數:設計
public typealias ButtonCallback = (buttonIndex: Int, buttonTitle: String) -> Void
可是這破壞了一切...當調用 show 方法時,ButtonCallback 方法此時須要兩個參數,而不是原來的一個了。code
// 用法 BananaAlertView.show( withTitle: "This is Bananas", message: "Someone has been monkeying around ?", dismissButtonText: "Banana", // 破壞了原來的調用 // 閉包須要帶有兩個參數:buttonIndex 和 buttonText dismissButtonCallback: { buttonIndex in // 具體實現 })
因而咱們該怎麼辦?此時參數對象就該上場了!
解決方案是爲閉包建立一個參數對象:
public class BananaAlertView { // 參數對象 public struct ButtonCallbackParameters { let buttonIndex: Int let buttonTitle: String } // 如今只須要一個參數 public typealias ButtonCallback = (parameters: ButtonCallbackParameters) -> Void public static func show( withTitle title: String, message: String, dismissButtonText: String, dismissButtonCallback: ButtonCallback) { // 具體實現 } } BananaAlertView.show( withTitle: "This is Bananas", message: "Someone has been monkeying around ?", dismissButtonText: "Banana", // 參數對象包含全部調用者須要的參數 dismissButtonCallback: { parameters in if parameters.buttonTitle == "Banana" { // 具體處理代碼 } })
如今須要添加額外的參數時,代碼依舊能工做得很是好。buttonCallback
徹底不須要變更。
public struct ButtonCallbackParameters { let buttonIndex: Int let buttonTitle: String // 新參數 let buttonCount: Int }
固然,你也能夠輕鬆刪除或移除參數:
public struct ButtonCallbackParameters { let buttonIndex: Int // 下個版本中移除 buttonTitle @available(*, deprecated=2.0) let buttonTitle: String let buttonCount: Int }
固然,能夠重構方法時用更通用的方式來得到愈來愈多的參數:
public class BananaAlertView { // 顯示警告視圖時,視圖選項不是必須的 // 這裏可以提供默認值 public struct AlertViewOptions { public let dismissButtonText = "Bananana" public let tintColor = UIColor.yellowColor() public let animationDuration: NSTimeInterval = 1 } public static func show( withTitle title: String, message: String, options: AlertViewOptions) { // 具體實現 } }
和其餘設計模式同樣,學會和用好徹底是兩件事,知道它們是好事,可是在使用前須要權衡一下。找到最佳的平衡點是咱們碼農的工做,須要不斷努力才能找到最佳實踐?。
對於參數對象來講,好處是可以爲將來預留 API,可是這樣的預留是有負擔的。你不能爲此給每一個方法和閉包都新建一個新結構體。
因此,請明智的使用!
最後,我強烈推薦觀看 @modocache 演講的完整視頻。
本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg。