Swift: 帶有關聯(lián)類型的協(xié)議是什么樣的?

作者:Natasha The Robot,原文鏈接,原文日期:2016-07-28
譯者:jseanj;校對:saitjr;定稿:CMB

最近我做了一個關于帶有關聯(lián)類型的協(xié)議(PATs, Protocols with Associated Types)的演講,我本來還覺得觀眾對這個已經(jīng)耳熟能詳了,但事實卻相反。

很多人并不知道 PATs 是什么——這我應該預料到的,因為我自學就用了一段時間。因此我想當面講解下,尤其是這些東西比較難理解,而且我也沒能找到很好的解釋。

Gwendolyn Weston 在東京 try! Swift 大會上給出的解釋對我很有幫助(視頻在這)。因此文中的示例是受她的演講啟發(fā)。Pokemon 將會出現(xiàn)...

在 PATs 之前

目前我在 Pokemon Go 中是 9 級,我聽說(感謝我的私人教練 @ayanonagon)所有的 Pokemon 有一些共同的特征,比如攻擊能力。

對于從 Objective-C 或者其他面向對象語言遷移過來的人來說,使用一個具有所有共同功能的 Pokemon 子類是吸引人的。由于每一個 Pokemon 具有不同的攻擊能力——光、水或者火等等——我們可以在我們的子類中使用泛型。

// 我們必須確保泛型 Power 有初始化方法
protocol Initializable {
    init()
}
 
// Pokemon 子類
// 每一個 Pokemon 有一個不同的 Power, 
// 因此 Power 是泛型
class Pokemon<Power: Initializable> {
    
    func attack() -> Power {
        return Power()
    }
}

此時,我們有不同的 Power 類型:

struct ??: Initializable { // 實現(xiàn) }
struct ??: Initializable { // 實現(xiàn) }
struct ??: Initializable { // 實現(xiàn) }

現(xiàn)在,其他的 Pokemon 可以從我們的 Pokemon 基類繼承,然后他們自動的包含了攻擊方法!

class Pikachu: Pokemon<??> {}
class Vaporeon: Pokemon<??> {}
 
let pikachu = Pikachu()
pikachu.attack() // ??
 
let vaporeon = Vaporeon()
vaporeon.attack() // ??

問題是我們使用的是繼承。如果你看了 Dave Abrahams 在 WWDC 上的 Swift 中面向協(xié)議編程,你現(xiàn)在的腦海里看到的應該是 Crusty 的臉...

使用繼承的問題是雖然剛開始的意圖是好的,但最終隨著意外的發(fā)生事情會變得越來越糟(比如 Pokemon Eggs 不能攻擊)。為了大家更好的理解,我強烈推薦大家讀讀 Matthijs Hollemans 的 Mixins and Traits in Swift 2.0。

畢竟,就像 Dave Abrahams 所說的,Swift 是一門面向協(xié)議的語言,所以我們需要改變面向對象的思維模式。

你好,PATs

讓我們用 PATs 來代替繼承!相比于繼承所有東西,我們可以創(chuàng)建一個專注于 Pokemon 攻擊能力的協(xié)議。記住,由于每一個 Pokemon 有不同的 Power,因此我們需要把它變成泛型。

protocol PowerTrait {
    // 就是這樣!關聯(lián)類型只是協(xié)議中表示泛型的一種語法
    associatedtype Power: Initializable
    
    func attack() -> Power
}
 
extension PowerTrait {
    // 通過協(xié)議擴展,我們現(xiàn)在有一個默認的攻擊方法 
    func attack() -> Power {
        return Power()
    }
}

現(xiàn)在,每一個遵循 PowerTrait 協(xié)議的 Pokemon 不必繼承就會具有攻擊能力了。

struct Pikachu: PowerTrait {
    // 由于我們使用的是默認的攻擊方法,就像在繼承時我們指定了泛型一樣,我們也必須指定關聯(lián)類型的類型
    // 注意,這仍然被稱為 typealias,但是在 Swift 的未來版本中會變成 associatedtype
    associatedtype Power = ??
}
let pikachu = Pikachu()
pikachu.attack() //??
 
struct Vaporeon: PowerTrait {
    // 當 attack 方法被重寫后,
    // 基于方法標識,?? 會被推斷為關聯(lián)類型
    func attack() -> ?? {
        // 自定義的攻擊邏輯
        return ??()
    }
}
let vaporeon = Vaporeon()
vaporeon.attack() //??

總結

就是這樣!帶有關聯(lián)類型的協(xié)議對于支持泛型的協(xié)議是一個新奇的術語。通過使用 PATs 這樣強有力的工具我們獲得了優(yōu)雅的組合而不是糟糕的繼承。

為了更多的了解 PATs 的限制以及更深入的學習,我強烈推薦 Alexis Gallagher 的演講

玩得愉快。

本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權,最新文章請訪問 http://swift.gg

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Swift的編程范式 編程范式是程序語言背后的思想。代表了程序語言的設計者認為程序應該如何被構建和執(zhí)行。常見的編程...
    Bobby0322閱讀 2,679評論 4 43
  • 第一章.面向對象與面向協(xié)議編程 本書是關于面向協(xié)議編程。當蘋果2015年的開發(fā)者大會上發(fā)布了Swift2,他們也宣...
    醬油不愛醋閱讀 1,500評論 0 7
  • 30個缺點 1.懶2.不愛動腦3.沒計劃4.執(zhí)行力差5.不愛喝水6.不堅持7.胖8.對顧客關心不夠9.沒責任心10...
    丹丹__7ea1閱讀 341評論 0 0
  • 很多東西看的到,感覺的到,為何就是抓不???沒有方法方式!世間萬千法,沒有提綱挈領的東西,你即使想到,一心向往,用盡...
    縱情嬉戲天地間閱讀 132評論 0 0
  • 五月,是精彩的!五月,是多彩多樣的!五月,是幸福的!讓我們用視覺、聽覺、味覺、觸覺………去感受五月吧! 語文周活動...
    lulu美玲閱讀 911評論 0 1

友情鏈接更多精彩內容