這是一個能展示(之前的方式)有多殘暴的例子:
class PresentErrorViewController: UIViewController {
var errorViewIsShowing: Bool = false
func presentError(message: String = “Error!", withArrow shouldShowArrow: Bool = false, backgroundColor: UIColor = ColorSalmon, withSize size: CGSize = CGSizeZero, canDismissByTappingAnywhere canDismiss: Bool = true) {
//寫下了復雜的,脆弱的代碼
}
}
//說一下矫钓,有100個class繼承了這個class
EveryViewControllerInApp: PresentErrorViewController {}
隨著項目的進行事情馬上變的明了:并不是每一個UIViewController需要這個error邏輯旦万,或是真的需要這個class所提供的每一個功能莽红。我團隊里任何一個人都可以輕易的在這個superclass里改點兒什么竭业,從而影響整個app。這就讓代碼變得脆弱国葬。還使得代碼呈現(xiàn)出了多態(tài)贤徒。當本應該是由子類決定它自己的行為,這里的superclass卻給幫著決定了胃惜。下面是在swift 2.0中我們?nèi)绾斡肞OP來更好的構(gòu)建這段代碼:
protocol ErrorPopoverRenderer {
func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool)
}
extension UIViewController: ErrorPopoverRenderer { //使所有遵從于ErrorPopoverRenderer協(xié)議的UIViewController具有一個presentError的默認實現(xiàn)
func presentError(message: String, withArrow shouldShowArrow: Bool, backgroundColor: UIColor, withSize size: CGSize, canDismissByTappingAnywhere canDismiss: Bool) {
//加上呈現(xiàn)error視圖的默認實現(xiàn)
}
}
class KrakenViewController: UIViewController, ErrorPopoverRenderer { //Drop the God class and make KrakenViewController conform to the new ErrorPopoverRenderer Protocol.
func methodThatHasAnError() {
//…
//拋出error泞莉,原因是Kraken海妖今天吃人會感到不適。
presentError(/*blah blah blah 好多參數(shù)*/)
}
}
看船殉,這里發(fā)生了很炫酷的事情鲫趁。我們不僅消除了上帝類的存在,還讓代碼更加的模塊化并增強了它的擴展性利虫。通過創(chuàng)建一個 ErrorPopoverRenderer協(xié)議挨厚,就會讓任何遵循了該協(xié)議的class具有呈現(xiàn)出一個ErrorView的能力。還不止這些糠惫,我們的KrakenViewController class不用必須實現(xiàn)presentError這個函數(shù)疫剃,因為我們擴展了UIViewController,讓它提供了一個默認實現(xiàn)硼讽。
唉不過等下巢价!這有個問題!我們每次想要呈現(xiàn)一個ErrorView的時候都必須要去實現(xiàn)每一個參數(shù)固阁。這就有點兒讓人不爽了壤躲,因為我們不能在protocol協(xié)議函數(shù)聲明中為參數(shù)提供默認值。
我還挺喜歡這些參數(shù)的备燃!更糟的是在讓代碼更具模塊化特征的過程中我們引入了復雜度碉克。還是繼續(xù)吧,用swift 2.0中新加的一個小妙招來多少的補償一下:
protocol ErrorPopoverRenderer {
func presentError()
}
extension ErrorPopoverRenderer where Self: UIViewController {
func presentError() {
//在這里加默認實現(xiàn)并齐,并提供ErrorView的默認參數(shù)漏麦。
}
}
class KrakenViewController: UIViewController, ErrorPopoverRenderer {
func methodThatHasAnError() {
//…
//拋出error客税,原因是Kraken海妖今天吃人會感到不適。
presentError() //Woohoo! 沒有參數(shù)了撕贞!我們現(xiàn)在有默認實現(xiàn)了更耻!
}
}
好了,現(xiàn)在看起來已經(jīng)很不錯了麻掸。我們不僅消除了這些煩人的參數(shù)酥夭,還用swift 2.0的新特性在protocol的層級上用Self給了presentError一個默認實現(xiàn)。用Self意味著當且僅當協(xié)議的遵循者是繼承自UIViewController的情況下脊奋,這個擴展才會有效。
這就讓我們能夠把ErrorPopoverRenderer真的當做是一個UIViewController疙描,而甚至不需要對后者做擴展诚隙!更棒的是,從現(xiàn)在開始起胰,Swift的運行時是以靜態(tài)調(diào)度而非動態(tài)調(diào)度去調(diào)用presentError()方法久又。大致的意思就是我們在函數(shù)調(diào)用點給presentError()方法增強了一點性能。