如標題所示,這次我們將探討物件導向。
我大學時候念的是資訊相關科系,四年級時研究室每周都有使用Smalltalk的物件導向課程。那位教授非常有趣,不僅講程式,還會從日常生活中不斷引入物件導向的例子,讓我也陶醉於這樣的習慣之中。
然而,這種習慣意外地對提升生活品質有幫助……希望大家也能與我一樣養成這樣的習慣。(一旦習慣後,程式設計的視角會逐漸融入日常生活,強烈推薦!)
我認為這是我們工程師不能避開的道路,希望大家也能發掘出來。
當我初次接觸物件導向時,遇到的障礙主要有以下幾點:
這些是周圍不少人培訓時遇到的障礙。
不過,我個人認為透過「將程式視為現實世界中的物品(物件)」來整理思路,理解會有所進展。如果大家也有可以這樣比喻的意見,歡迎留言告訴我。
這次我將以RPG角色創建為例,來探討不論使用哪種語言都能一致運用的「四大原則」,希望能以視覺化的方式讓大家理解。
首先是所有基礎的概念。
類別是 「定義共同規則和項目的設計圖」。
實體則是具體的類別化身。
當大家向別人解釋事情時,常常會先介紹抽象的概念。
如果對方似乎能理解,會接著加上 「例如」這個用語,然後提出具體的案例。那個「具體的案例」的提出過程,正是物件導向中的「實體化」的近似意象。
用RPG角色來比喻如下:
類別

實體

// kotlin程式碼示例
val hero = Warrior("阿爾斯", hp=120, strength=85)
val knight = Warrior("希爾瓦", hp=180, strength=60)
val boss = Warrior("達克隆", hp=500, strength=200)
hero.attack() // 可以呼叫相同的方法
boss.attack() // 不過因為strength不同,結果也會不同
物件導向的重要防護要素,便是 「封裝」。

如果角色的「HP」這個重要數據,任何人都可以從任何地方將其改為 HP = 0,那麼遊戲平衡很快就會崩潰。(這就是作弊…)
防護牆內部(資料)
防護牆表面(方法)
要有效增加角色的變化,知識在於 「繼承」。

從頭開始創建「魔法師」或「戰士」是相當艱難的。因此,我們創建一個共同的「角色」父類別。
金字塔頂端(父類別:Character)
金字塔下層(子類別:Wizard / Warrior)
專欄:繼承與聚合的區別
雖然這次不會詳細說明,但在物件間的關係中,還有一個概念是 聚合。繼承與聚合可以如下區分。
繼承(Inheritance):
「A是B的一種類型(Is-a關係)」,就像人類或魔族。
聚合(Aggregation):
「A擁有B(Has-a關係)」,就像可拆卸的裝備一樣。
(例:劍士持有劍,魔法師持有魔法杖)
若想讓「戰士」擁有「劍」功能的話,若錯誤地使用了「繼承」……
class 戰士 extends 劍 (戰士是劍的一種),就會產生不明人類或武器的奇妙結構。
而若使用「聚合」,只需在戰士的物件中持有「劍物件」即可。
最後,透過相同的「攻擊」指令,讓角色展現各自的個性,這個機制便是 「多態性(Polymorphism)」。
試著想像一下給全體隊伍發出 attack()(攻擊)的指令的場景。
大家覺得怎麼樣?
首先,請珍惜這些視覺化,開始寫程式吧!
同時,試著將周遭事物想象為這是類別…這是實體…也許會很有趣。
專欄:為何要學習「範式」
這是我的看法,儘管編程的語言文法各異,
但是,不論是哪種語言,理解物件導向的範式與否對語言學習的效率會有很大的影響。
僅僅記住文法像是「記單字」,而理解範式則像是「安裝思維的作業系統」。一旦安裝了這個OS,即使遇到新的語言,也能以「這個語言該如何表達?」的視角,驚人地順利掌握。