程式碼的「領地」
大家一定對我們學習自訂型態、迴圈、控制流的時候,最常出現的一個句型很有印象:
...
{
和}
包裹的程式碼...
我們在系統指令print()
和介紹自訂指令的時候,也看到了很多次(
和)
的組合(雖然現在括號裡面並沒有任何東西),附帶一提,在之後的課程我們介紹「集合」這個概念的時候,還會用到[
和]
的組合。
這些成雙成對的左右括號,很像在宣示自己的領地一般。
print("這裡的字我會印出來!") "這裡的字我不管"
struct 決鬥者 { func 劈砍() {} } struct 暗影刺客 {} var kita = 決鬥者() kita.劈砍() // 完全正確的執行 var eeec = 暗影刺客() eeec.劈砍() // 回報錯誤 劈砍() // 也回報錯誤
這是「物件導向程式設計」的特色之一,現在流行的大多數程式語言,例如C++
、Python
、Java
,以及我們正在學習的Swift
都屬於物件導向程式語言,在傳統、古老的程式語言裡面,我們傾向於將程式碼看做一系列指令的集合,例如劈砍()
這個在角色扮演遊戲中常見的技能,或許會被這麼描述:
定義 Kita Kita.拿起武器(2) Kita.舉起雙手(角度:115) Kita.同時揮動雙手(力道:30)
這些指令會基礎到電腦可以直接認得,在撰寫程式的時候,工程師實際上並不介意是kita
還是eeec
在執行這個動作,他們將指令分解成基本到像是1+1=2
的單位,然後像樂高積木一樣組合成自己需要的功能,接著使用在任何定義出來的角色或物體上,程式碼總是會執行成功,這種風格很像是「工程師隨時都在設計程序,來教導電腦怎麼處理任務」,因此稱為「程序導向程式設計」。
整個程式將會由「功能」切割,邏輯也由工程師寫作的方式完全定義,最主要的程式碼通常放在一個main
之類的指令中間,執行時會循序的做完各個基礎指令,沒有什麼嚴格的領地概念。
物件導向程式設計,則是將程式由「物件」切割,在使用這些物件的指令(例如劈砍()
)時,電腦根本不知道、也並不介意劈砍()
這個動作是如何完成的,電腦只需要確定使用劈砍()
的物件類別,確實認得這種指令,他就會將任務丟進該物件的領地,由該物件自己處理,而之所以這些物件具備處理這些指令的能力,乃是因為工程師事先就在這些物件裡面寫好了所有它們可能會用到的指令。
整個程式會充滿這樣的事件,每個物件都是可互動的,就好像一台台迷你電腦一樣,這種「工程師設計了大量的物件,並教導他們怎麼處理任務,再藉由物件的分工組合成程式」的風格,就是「物件導向程式設計」。
一個最經典的分辨程序導向與物件導向差異的實例,就是食譜:
程序導向
- 將牛蕃茄洗淨切片或塊
- 洋蔥、紅蘿蔔去皮切小塊
- 高麗菜洗淨切片
- 培根切條狀準備使用
- 培根炒香後,再加入洋蔥及紅蘿蔔拌炒3分鐘
- 放入牛蕃茄及高麗菜,倒入水與蕃茄醬拌勻
- 煮沸後中小火繼續煮約25~30分鐘
- 撒上黑胡椒粒、義大利香料以及鹽調味即完成
物件導向
- 定義鍋子、培根、高麗菜...
- 處理好培根
- 處理好高麗菜
- 處理好洋蔥
- 處理好紅蘿蔔
- 處理好牛番茄
- 處理好調味料
物件導向的main
實際上根本不關心食材是怎麼「處理好」的,設計處理過程是鍋子、培根、高麗菜這些物件領地的責任,它也不必然要依照程序導向這樣的順序執行,只要在鍋子的拌炒()
、煮沸()
檢查食材狀態無誤即可。