做者:Natasha The Robot,原文連接,原文日期:2016-07-28
譯者:jseanj;校對:saitjr;定稿:CMBgit
最近我作了一個關於帶有關聯類型的協議(PATs, Protocols with Associated Types)的演講,我原本還以爲觀衆對這個已經耳熟能詳了,但事實卻相反。github
不少人並不知道 PATs 是什麼——這我應該預料到的,由於我自學就用了一段時間。所以我想當面講解下,尤爲是這些東西比較難理解,並且我也沒能找到很好的解釋。編程
Gwendolyn Weston 在東京 try! Swift 大會上給出的解釋對我頗有幫助(視頻在這)。所以文中的示例是受她的演講啓發。Pokemon 將會出現...swift
目前我在 Pokemon Go 中是 9 級,我據說(感謝個人私人教練 @ayanonagon)全部的 Pokemon 有一些共同的特徵,好比攻擊能力。app
對於從 Objective-C 或者其餘面嚮對象語言遷移過來的人來講,使用一個具備全部共同功能的 Pokemon 子類是吸引人的。因爲每個 Pokemon 具備不一樣的攻擊能力——光、水或者火等等——咱們能夠在咱們的子類中使用泛型。ide
// 咱們必須確保泛型 Power 有初始化方法 protocol Initializable { init() } // Pokemon 子類 // 每個 Pokemon 有一個不一樣的 Power, // 所以 Power 是泛型 class Pokemon<Power: Initializable> { func attack() -> Power { return Power() } }
此時,咱們有不一樣的 Power 類型:工具
struct ?: Initializable { // 實現 } struct ?: Initializable { // 實現 } struct ?: Initializable { // 實現 }
如今,其餘的 Pokemon 能夠從咱們的 Pokemon 基類繼承,而後他們自動的包含了攻擊方法!學習
class Pikachu: Pokemon<?> {} class Vaporeon: Pokemon<?> {} let pikachu = Pikachu() pikachu.attack() // ? let vaporeon = Vaporeon() vaporeon.attack() // ?
問題是咱們使用的是繼承。若是你看了 Dave Abrahams 在 WWDC 上的 Swift 中面向協議編程,你如今的腦海裏看到的應該是 Crusty 的臉....net
使用繼承的問題是雖然剛開始的意圖是好的,但最終隨着意外的發生事情會變得愈來愈糟(好比 Pokemon Eggs 不能攻擊)。爲了你們更好的理解,我強烈推薦你們讀讀 Matthijs Hollemans 的 Mixins and Traits in Swift 2.0。翻譯
畢竟,就像 Dave Abrahams 所說的,Swift 是一門面向協議的語言,因此咱們須要改變面向對象的思惟模式。
讓咱們用 PATs 來代替繼承!相比於繼承全部東西,咱們能夠建立一個專一於 Pokemon 攻擊能力的協議。記住,因爲每個 Pokemon 有不一樣的 Power,所以咱們須要把它變成泛型。
protocol PowerTrait { // 就是這樣!關聯類型只是協議中表示泛型的一種語法 associatedtype Power: Initializable func attack() -> Power } extension PowerTrait { // 經過協議擴展,咱們如今有一個默認的攻擊方法 func attack() -> Power { return Power() } }
如今,每個遵循 PowerTrait 協議的 Pokemon 沒必要繼承就會具備攻擊能力了。
struct Pikachu: PowerTrait { // 因爲咱們使用的是默認的攻擊方法,就像在繼承時咱們指定了泛型同樣,咱們也必須指定關聯類型的類型 // 注意,這仍然被稱爲 typealias,可是在 Swift 的將來版本中會變成 associatedtype associatedtype Power = ? } let pikachu = Pikachu() pikachu.attack() //? struct Vaporeon: PowerTrait { // 當 attack 方法被重寫後, // 基於方法標識,? 會被推斷爲關聯類型 func attack() -> ? { // 自定義的攻擊邏輯 return ?() } } let vaporeon = Vaporeon() vaporeon.attack() //?
就是這樣!帶有關聯類型的協議對於支持泛型的協議是一個新奇的術語。經過使用 PATs 這樣強有力的工具咱們得到了優雅的組合而不是糟糕的繼承。
爲了更多的瞭解 PATs 的限制以及更深刻的學習,我強烈推薦 Alexis Gallagher 的演講。
玩得愉快。
本文由 SwiftGG 翻譯組翻譯,已經得到做者翻譯受權,最新文章請訪問 http://swift.gg。