淺談 Protocol-Oriented Programming — Protocol Extension

Steven Chou
Aiworks
Published in
5 min readOct 6, 2017

--

過去我們在學程式時,都會聽到一個名詞 — 物件導向 (OOP, Object-Oriented Programming) ,創造出許多元件,然後重複利用它們,類別繼承則是其中最常見的設計模式。

在 iOS 開發的領域中,過去 Objective-C 時期,也都是使用物件導向這套設計模式,直到 Apple 推出了 Swift 這套新的程式語言後,有了些變化。

Swift 被 Apple 官方定義為 Protocol-Oriented Programming,並在 Swift 2 時,利用 Protocol Extension 大幅改進了 Swift 的標準函式庫,這項變動也讓我們可以利用 extension 的方式來強化一些標準函示 (Ex: String, Int, Double…等等)

在上一段裡,我們看見了 iOS 開發的轉捩點,就是在 Protocol Extension。過去我是寫 Java 跟 Android 直到近一年才開始寫 iOS,所以物件導向的觀念一直深植在腦中,當我第一次看到 Protocol 時,就直接把它當作 Java 的 Interface 看待 (class / function 的規格書),近期深入研究後發現,Objective C 時期的 Protocol 的確是那麼使用,但現在的它已經再進化。

接下來我會用一些範例來讓大家更了解 Protocol Extension 這項在 Swift 語法中的強大功能。

我們先創建一個 Protocol — Engineer,裡頭有兩個屬性 team 以及 canDevelopiOS

我們利用 Protocol 去規範了開發者在創建一個工程師時,必須要填入他的所屬團隊,以及會不會開發 iOS。

這邊 Protocol 的用法,就如同 Java 的 Intetface (介面),Protocol 成了一個規格書/設計圖,讓 Steven 這個 Struct 去實作它,必須按照 Protocol 的規範,實作所需的屬性。

回到程式碼,照理來說,在 iOS team 裡面的工程師,應該都會開發 iOS 才對,只是不一定會寫 Swift,所以我們在這邊再加上另一個 Protocol,並實作到 Steven 上:

這時會覺得 canDevelopiOS 這個屬性有點多餘,但是如果將程式碼拆解成不同的 Protocol ,讓物件去實作他們,便會產生出這般情況。

Protocol Extension 此時就要跳出來展現它令眾人為之瘋狂的能力了!

廢話不多說,直接上 code:

這邊我們可以看到,Protocol 展現了它有別於其他語言的特殊能力,它能讓我們在 Extension 時去執行一個抽象化的動作,爾後如果有 Class / Struct / Enum 去實作它,便能有 extension 裡頭所定義的變數或函式,你可以想像成在 Extension 中先塞入預設值的概念。

這讓我們的 code 有更大的彈性,像上面這段程式,我們判斷了有實作 Engineer 的程式,是否也實作了 Swiftable 這個 Protocol。如果會 Swift 就等於他會開發 iOS 嘛,於是在 Extension Engineer 這邊,會去塞個預設值給 canDevelopiOS。

我們再創造另一個工程師出來:

因為 Sam 是 Android team 底下的成員,所以常理來說他並不會寫 iOS 程式,我們就不需要再去多做一個判斷,因為在 Extension Engineer 時就已經做好了。

有一天,Sam 突然奮發向上,把 iOS 開發的技能也練就起來,我們的程式碼可以依照這個需求,來做些微調:

我們把 canDevelopiOS 這個屬性再次寫進 Struct,這時候在 init Sam 的時候,就可以修改掉原本的預設值。

如果今天 Sam 是去學 Swift 開發的話,我們就可以用跟 Steven 一樣的作法,讓他也去實作 Swiftable:

我們利用了 Protocol 的特性,去多掛一個能力到 Sam 身上。

因此我們在開發時可以把每個能力、功用都寫成一個 Protocol,讓不同的元件去掛上他們,就像在穿裝備一樣,想要有遠程攻擊能力,武器就拿弓;想玩近戰類型的,就拿劍。

如果有什麼特殊需求,還可以在實作時,做一些小修改,這樣的寫法讓 Swift 更為強大、充滿彈性。

另外,我們在一開始有提到說現在 Apple 官方將大多數的標準函式庫都改用 Protocol 的方式去撰寫,這也告訴我們,我們可以自行撰寫一些外掛,去擴充這些函式庫,我們拿 Engineer 這個 Protocol 來做個範例:

這時我們去印出 Steven 物件下的 Description

因為我們加上了 where 這個關鍵字,讓擴充部分局限於有實作 Engineer 這個 Protocol 的物件,所以並不會影響到其他有實作 CustomStringConvertible 的物件。

多多利用 Protocol 除了重複使用率變高,還有另一個好處是,在未來要替專案加上測試時,將會變得容易建置,畢竟規範都寫好了。若硬要說它的壞處的話,這種寫法會將功能切得太碎,開發時間也會拉長一些,如何管理也得好好思考。

在搜尋資料時,有看到一個對於專案開發,該選哪個設計模式的說法:「今天如果你所做的專案,只是個小專案,那可以直接使用 OOP 的方式去做完它即可。但如果所要開發的專案較為龐大,又需要做 Unit Testing 的話,那就使用 POP 的設計模式去開發,一開始就先把規格定好,避免未來需要花更多的時間回頭償還技術債。」

不過在 WWDC 時,主講人已直白地告訴大家:「 Don’t start with a class, start with a protocol. 」

所以從今天開始,我們就盡量使用 Protocol-Oriented Programming 的開發模式來撰寫專案吧!

--

--