軟體設計

什麼是物件導向程式設計(OOP)?和程序導向有什麼不同?

學習程式設計時,一定會遇到這個詞。

閱讀 4 分鐘
什麼是物件導向程式設計(OOP)?和程序導向有什麼不同? 封面圖

什麼是物件導向程式設計(OOP)?和程序導向有什麼不同?

學習程式設計時,一定會遇到這個詞。

「這段程式碼應該用物件導向的方式撰寫。」

第一次聽到時,確實會讓人不知所措。程序導向又是什麼?物件導向到底有什麼不同?一時很難掌握。

先說結論:程序導向著重於「要依照什麼順序做什麼」,物件導向則更重視「誰來負責這件事」。差別在於,是否將資料與處理資料的功能整合在一起。

本文會用點咖啡的例子,輕鬆說明兩者的差異,並展示在實際程式碼中會如何不同。


程序導向程式設計就像料理食譜

程序導向顧名思義,著重於「程序」,也就是順序。

資料和處理資料的函式分開存在,程式會依照順序由上往下執行。

想像料理食譜就很貼切:清洗、切碎、翻炒,再盛盤。把這個順序原封不動寫進程式碼,就是程序導向。

來看一個簡單的帳戶範例。

var balance = 10000  // 資料

func deposit(amount: Int) {   // 功能分開
    balance += amount
}

deposit(amount: 5000)
print(balance)
// 輸出: 15000

balance 這份資料暴露在外部,而 deposit 函式會直接修改它。

對小型程式來說,這反而簡單又快速。問題會在程式變大時出現。

當帳戶增加到100個,修改餘額的函式又散落各處時,要追蹤數值在哪裡被改動會變得非常困難。


什麼是物件導向程式設計(OOP)?

物件導向會將資料與功能整合在一起。這個集合稱為「物件」。

以帳戶為例,就是把「餘額」資料和「存款」功能整合成一個單位。

把剛才的帳戶改成物件來看看。

class Account {
    private var balance = 10000   // 將資料隱藏在內部

    func deposit(_ amount: Int) { // 功能也一起放入
        balance += amount
    }
    func show() { print(balance) }
}

let myAccount = Account()
myAccount.deposit(5000)
myAccount.show()
// 輸出: 15000

balance 現在被隱藏為 private。外部無法再任意修改餘額,只能透過 deposit 等指定的管道存取。

這就是物件導向的核心:保護資料,並明確定義「誰負責這件事」。

用點咖啡來比喻:程序導向是自己磨豆、煮水,所有事情都自己做;物件導向則是交給別人,說一聲「咖啡師,請給我一杯美式」。怎麼製作,就由咖啡師物件自行負責。


OOP 的4個核心特徵

物件導向有四根支柱。術語看似困難,但概念其實很簡單。

  • 封裝:隱藏資料,只允許透過指定管道存取(就像上面的 private)
  • 繼承:繼承既有類別的功能並加以重複使用
  • 多型:即使是相同指令,不同物件也會有不同的行為
  • 抽象化:隱藏複雜的內部細節,只公開必要的部分

多型尤其強大。要求「叫一聲」時,狗會汪汪叫,貓會喵喵叫。指令只有一個,但每個物件會自行做出不同反應。

單一 Account 物件同時負責餘額與存款
單一 Account 物件同時負責餘額與存款

什麼時候使用物件導向,什麼時候程序導向比較好

物件導向不一定永遠是正解,應該依情境選擇。

情境 適合的方式
短程式碼、一次性計算 程序導向
資料流程簡單且依序進行 程序導向
規模大且持續成長的專案 物件導向
多人協作的程式碼 物件導向
相似概念反覆出現 物件導向

規模小且簡單時,程序導向反而更俐落;如果是規模大、複雜且需要長期維護的程式碼,物件導向就能發揮優勢。

規模小就依序處理,變大變複雜後則按責任拆分會更輕鬆
規模小就依序處理,變大變複雜後則按責任拆分會更輕鬆

程序導向設計順序,物件導向設計責任。

面試時會這樣問

Q. 程序導向和物件導向最大的差異是什麼? A. 資料與功能的關係。程序導向將資料與函式分開,依順序執行;物件導向則將兩者整合成物件,按責任單位管理。因此規模越大,越有利於維護與協作。

Q. 為什麼封裝很重要? A. 它能阻止外部直接修改資料,減少非預期的變更。只能透過指定方法存取,因此更容易追蹤錯誤;即使修改內部實作,也較不會影響外部程式碼。


術語看起來很宏大,但核心其實只有一件事:「要如何處理資料?」

從小段程式碼開始練習將其封裝成物件,很快就能掌握訣竅。希望你能運用今天學到的內容,重構自己程式碼中的一小部分。

延伸閱讀