初探物件導向程式設計 OOP (一)

Kash Yang
7 min readJul 6, 2023

--

最近接觸到很多零經驗的學員,從最基本的物件導向開始學起,過程中也是遇到一些問題,所以今天來跟大家聊一下怎麼學物件導向程式設計 (Object Oriented Programming),也就是大家俗稱的 OOP

我們首先要先知道,寫程式的方式有很多種 (有興趣可以去查 Programming Paradigm),而物件導向只是其中一種。藉由描述不同物件內還有物件之間的行為來讓人編寫程式的一種程式設計方式。

既然叫做物件導向,那我們肯定要先理解一件事:物件

什麼是物件?

英文叫做 Object,雖然沒有什麼明確的定義,但我們可以暫時將這個概念對應到生活中的所有擁有實體的物體:桌子、椅子、毛小孩、車子…等等。

什麼是物件導向?

這是我自己對物件導向的理解:

物件導向就是嘗試將所有東西都描述成物件的一種思考邏輯。

包含那些存在但摸不到的東西,像是空氣、無線電波、極光。抑或是沒有實體、人類想像出來的東西,像是概念、思想等等這類抽象的東西。這些東西在物件導向的世界中,只要有規範可以描述,都可以成為一個物件。

注意我這邊的用詞,這邊想表達的是:

規範不等於物件本身,規範是一張紙,是一份合約,透過這張紙做出來的東西才是物件,才擁有實體

接下來我們會將這個想法從生活中帶回程式設計裡面,討論 OOP 中,怎麼利用規範來描述一個物件

在 OOP 中利用類別 (class),來表示物件的規範,接下來我們都以 Kotlin 為主來說明,一個 class 基本上會包含這些元素

1. 類別名稱 class name

非常直覺,就是這個類別的名字

2. 類別成員 class member

分為兩種:

  • 資料成員 (Field member):說法不一,屬性 (property)、欄位 (field)、變數 (member data/variables),這些說法都有,指的都是資料成員,表示類別中有哪些資料 (看例子會比較有感覺)
  • 方法成員 (Method member):描述這個類別提供什麼功能可以操作使用

3. 類別建構子 class constructor

敘述如何生成這個類別實例 (Instance) 的方法,以及生成實例的時候需要有哪些參數

了解了基本的 class 元素之後,我們現在來試著簡單設計一個人的 class,叫做 Person ,他可能會像這樣:

// "Person" 就是class name
// constructor說明了生成Person需要輸入firstName, 以及lastName
class Person constructor (
var firstName: String, //名
val lastName: String //姓
) {
// Person的 class member 有五個,姓、名、身高、體重以及地址
var height: Int = 0 //身高
var weight: Int = 0 //體重
var address: String? = null //地址

// Person的 class method有二個
fun eat() { /*...*/ } //吃
fun sleep() { /*...*/ } //睡覺

}

看完這個 class 的 code 應該會針對 class member 有點疑問,為什麼是五個?不是只有三個嗎?

因為 Kotlin 幫你做了一些事情,讓工程師能少寫一點 code。這邊我們先借用 Java 的例子來看一下會清楚很多:

class Person {

// Person的 class member 有五個,姓、名、身高、體重以及地址
public String lastName; // 姓
public String firstName; // 名
public int height = 0; // 身高
public int weight = 0; // 體重

@Nullable
public String address; // 地址

// constructor, 需要輸入姓、名做參數來生成物件實例
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

// Person的 class method有二個
public void eat() { /*...*/ } // 吃
public void sleep() { /*...*/ } // 睡覺
}

各位現在可以看得出來,Kotlin 幫忙把生成實例的時候要帶入 constructor 的必要參數,放入你的 class member 裡囉。

有了這個物件的描述,我們就可以生成這個物件的 instance 了,在 OOP 中常常使用 new 這個字來形容這個實體化的行為,例如:我 new 了一個 Person、new 一個 Person 的實體。

在 Kotlin 中生成一個實例很簡單,因為 Kotlin 會自動判斷型別 (是哪一個 class),所以呼叫 constructor 並且帶入必要參數即可,Java 則是需要加上保留字 new 以及指定型別:

// Kotlin
val kash = Person("Kash", "Yang") // 自動判斷型別
val kash: Person = Person("Kash", "Yang") // 表明Kash是一個Person

//Java
Person kash = new Person("Kash", "Yang");

擁有實體之後,程式就能透過這個物件的實體,呼叫這個類別所提供的 method,來實現某些行為:

val kash = Person("Kash", "Yang")
kash.eat() // Kash 吃飯
kash.sleep() //Kash 睡覺

要注意每 new 一次實體出來,都會產生一個新的實例,雖然都是同樣的型別,但都是不同的個體

var kashA = Person("Kash", "Yang")  // 產生實體#1
kashA.eat() // kashA 吃飯

kashA = Person("Kash", "Yang") // 產生實體#2,並且把kashA指向的實體由#1改為#2
kashA.eat() // 一樣都是kashA 吃飯,但真正的實體已經由本來的 #1 變成 #2了

val kashB = Person("Kash", "Yang") // 產生實體#3

每一個物件的操作都是獨立的,kashA.sleep() 只會讓 kashA 去睡覺,跟 kashB實例沒有關係。

通過很多個這樣的物件彼此之間的排列組合、互動,來達到目的的程式設計方法,就是 OOP

不過這麼多物件要描述,我想到就累了,不是會寫到手很酸嗎?有沒有辦法省一些功?

當然有囉,所以我們下一篇來聊一下,什麼是繼承 (inheritance)

祝大家 happy coding ~

class 在 OOP 中是很基本的元素, 雖然在Kotlin中有很多變形,abstract classinner classdata classsealed classenum class 或是typealias的應用等等,但不用擔心,他的邏輯都是一樣的,只是有不同的特性而已,掌握 clas s的基本概念,就能掌握這些變形的應用!

相信很多人會去問身邊的朋友,或是會去 google OOP 是什麼,很快會得到

繼承封裝多型

這三個 OOP 最常被提到的特色。

但說實話,我認為直接看這個這對初學者沒太大幫助,反而又多了三個名詞要解釋,然後越挖越深,不懂的越來越多。

所以先掌握基本盤,暸解定義,以及物件導向是什麼東西,再來看特色才有意義

--

--