位於希臘Delphi的阿波羅神廟,曾刻有一句希臘文神諭(oracle) "γνῶθι σεαυτόν",翻譯為英文意思為 "Know yourself",「認清自己」是西方哲學非常基本的議題,也經常被後人引用,例如曾出現在「駭客任務」第一集,基努李維飾演的Neo被帶去祭師(Oracle)家裏,這句話就刻在廚房樑上。
學習物件導向也必須認清"self",因為若不懂 self,在物件導向的世界簡直就寸步難行。什麼是 "self"、為什麼需要?這對初學者來說,不只是語法問題,也是個哲學問題。
我們先用一個簡單範例,來說明物件導向程式中為什麼一定要用到 self。
假設我們想在App增加「通訊錄」功能,只包含3欄個人資料:姓名、手機號碼、好友標示,基本操作包括(「增刪查改」):
1. 新增一筆紀錄(至少需有姓名)
2. 刪除一筆紀錄(根據姓名或手機)
3. 搜尋紀錄(根據姓名或電話)
4. 更改資料(根據姓名,修改手機號碼)
5. 列印整份通訊錄
先以最容易實現的#1新增、#5列印兩功能做示範,函式化的程式如下:
// My Contacts -- functional programming
// Created by Heman, 2022/02/06
struct 個人資料 {
var 姓名: String
var 手機號碼: String
var 好友: Bool
}
func 新增(_ 人名: String, 手機: String = "", 好友嗎: Bool = false) -> 個人資料 {
return 個人資料(姓名: 人名, 手機號碼: 手機, 好友: 好友嗎)
}
func 列印通訊錄(_ 通訊錄: [個人資料]) {
for 個人 in 通訊錄 {
print(個人.姓名, 個人.手機號碼, 個人.好友 ? "❤️" : "")
}
}
var 我的通訊錄: [個人資料] = []
let 小胖 = 新增("小胖", 手機: "0912345678", 好友嗎: true)
let 小明 = 新增("小明", 手機: "0987654321")
let 小李 = 新增("小李(沒有手機)")
我的通訊錄 = 我的通訊錄 + [小胖, 小明, 小李]
列印通訊錄(我的通訊錄)
執行結果
小胖 0912345678 ❤️
小明 0987654321
小李(沒有手機)
傳統函式的概念非常簡單,就像所有的工作或流程,都可以簡化為「輸入 - 處理 - 輸出」三部分,函式也是同樣概念:
同樣的程式改為物件導向,也就是將函式包入 struct 宣告的資料類型裡面,修改如下,注意其中的函式(物件方法)如何使用 self:
// My Contacts -- object-oriented programming
// Created by Heman, 2022/02/06
struct 個人資料 {
var 姓名: String = ""
var 手機號碼: String = ""
var 好友: Bool = false
}
struct 通訊錄 {
var 內容: [個人資料] = []
mutating func 新增(_ 人名: String, 手機: String = "", 好友嗎: Bool = false) {
self.內容 = self.內容 + [個人資料(姓名: 人名, 手機號碼: 手機, 好友: 好友嗎)]
}
func 列印() {
for 個人 in self.內容 {
print(個人.姓名, 個人.手機號碼, 個人.好友 ? "❤️" : "")
}
}
}
var 我的通訊錄 = 通訊錄()
我的通訊錄.新增("小胖", 手機: "0912345678", 好友嗎: true)
我的通訊錄.新增("小明", 手機: "0987654321")
我的通訊錄.新增("小李(沒有手機)")
我的通訊錄.列印()
執行結果完全相同
小胖 0912345678 ❤️
小明 0987654321
小李(沒有手機)
物件方法的概念稍微比較複雜一些,除了輸出、輸入之外,還多了內部可以存取的屬性,在範例中,「新增()」目的是修改物件自己的屬性,所以不需要回傳值(輸出)。
簡單地說,內部存取的屬性,不管是要讀出還是要寫入,在物件方法裡就用 "self.屬性名稱" 來取用,而且在名稱不會混淆的情況下,這裡的 self 都可以省略,直接寫「屬性名稱」即可,也就是:
self.內容 = self.內容 + [個人資料(姓名: 人名, 手機號碼: 手機, 好友: 好友嗎)]
也可以寫成:
內容 = 內容 + [個人資料(姓名: 人名, 手機號碼: 手機, 好友: 好友嗎)]
總結起來,函式化方法是將資料(輸出、輸入)與工作(函式)分開,彼此獨立,觀念簡單明瞭,解決簡單的問題快又有效;物件導向的方法將某些資料與動作包在一起,外部的輸出、輸入仍然可以有,但重點放在內部資料(也就是物件屬性)的操作上,可以建構出強大物件來解決複雜問題。
註解
- self是自己、本身之意。在德國哲學體系中,將self細分為 ego「自我」,是自我意識的本體;人還有潛意識下的「本我」,稱為 id ,控制著隱藏在意識之下的慾望、情緒與本能;理性的部分稱為 super-ego「超我」,經過後天有意識的學習,昇華為道德、社會倫理、理智之所在。