跳轉至

建立 2026-11-12 更新 2026-11-12 SL HL

B3.1 單一類別的 OOP

單一類別的物件導向程式設計(Fundamentals of OOP for a single class)說明如何設計一個類別:定義屬性與方法、用建構子建立物件、用封裝保護資料,以及靜態成員與 UML 類別圖。這是 SL 與 HL 都要掌握的 OOP 基礎。

類別和物件有什麼關係?

  • 類別(class):物件的藍圖或模板,定義物件有哪些資料與行為。例如「學生」。
  • 物件(object):依類別建立的實體(instance),各自有自己的資料。例如「Amy」「Ben」兩位學生。
  • 屬性(attribute):物件的資料,例如姓名、年級。
  • 方法(method):物件能做的動作,例如加入成績、計算平均。
  • 建構子(constructor):建立物件時自動執行的特殊方法,用來設定初始值。

如何定義一個類別?

class Student:
    school = "IB Academy"          # 類別(靜態)屬性:所有物件共用
    count = 0

    def __init__(self, name, level):   # 建構子
        self.__name = name             # 私有屬性(名稱前加 __)
        self.__level = level
        self.__scores = []
        Student.count += 1

    # getter
    def get_name(self):
        return self.__name

    # setter:在修改前檢查資料
    def set_level(self, level):
        if level in ("SL", "HL"):
            self.__level = level
        else:
            raise ValueError("level 必須是 SL 或 HL")

    def add_score(self, score):
        if 1 <= score <= 7:
            self.__scores.append(score)

    def average(self):
        if not self.__scores:
            return 0
        return sum(self.__scores) / len(self.__scores)


amy = Student("Amy", "HL")
amy.add_score(6)
amy.add_score(7)
print(amy.get_name(), amy.average())   # Amy 6.5
print(Student.count)                   # 1
import java.util.ArrayList;

public class Student {
    private static int count = 0;              // 靜態屬性
    private String name;                        // 私有屬性
    private String level;
    private ArrayList<Integer> scores = new ArrayList<>();

    public Student(String name, String level) { // 建構子
        this.name = name;
        this.level = level;
        count++;
    }

    public String getName() {                   // getter
        return name;
    }

    public void setLevel(String level) {        // setter
        if (level.equals("SL") || level.equals("HL")) {
            this.level = level;
        } else {
            throw new IllegalArgumentException("level 必須是 SL 或 HL");
        }
    }

    public void addScore(int score) {
        if (score >= 1 && score <= 7) {
            scores.add(score);
        }
    }

    public double average() {
        if (scores.isEmpty()) return 0;
        int sum = 0;
        for (int s : scores) sum += s;
        return (double) sum / scores.size();
    }

    public static int getCount() {
        return count;
    }
}

什麼是封裝?

封裝(encapsulation) 把屬性設為私有(private),外部只能透過公開(public)方法存取。好處:

  • 保護資料:setter 可以先驗證,例如分數只接受 1–7,避免物件進入不合理狀態。
  • 隱藏實作:外部不需要知道分數用串列還是陣列存,日後修改內部實作也不會影響使用者。
存取修飾詞 Java Python 慣例 誰能存取
public public 一般名稱 任何地方
private private 名稱前加 __ 只有類別內部
protected(HL 繼承時用) protected 名稱前加 _ 類別內部與子類別

靜態成員和實例成員有什麼不同?

  • 實例(instance)成員:每個物件各有一份,例如每位學生的 name。
  • 靜態(static)成員:屬於類別本身,所有物件共用一份,例如 count 記錄已建立幾個學生。呼叫時用類別名稱,例如 Student.getCount()。

如何畫 UML 類別圖?

UML(Unified Modeling Language)類別圖用三格方框表示一個類別:類別名稱、屬性、方法。- 表示 private,+ 表示 public,底線表示靜態。

classDiagram
    class Student {
        -String name
        -String level
        -List~int~ scores
        -int count$
        +Student(name, level)
        +getName() String
        +setLevel(level) void
        +addScore(score) void
        +average() double
        +getCount()$ int
    }

推薦影音

Python OOP:類別與實例(Corey Schafer)

簡述:Corey Schafer 系列第一集,示範如何定義類別、__init__ 建構子、實例屬性與方法,以及 self 的意義,非常適合 Python 學生。

物件導向程式設計簡介

簡述:Programming with Mosh 說明 OOP 四大支柱,SL 學生先專注在「封裝」與「抽象」兩部分即可。

練習題

練習 1:名詞辨認

在 amy = Student("Amy", "HL") 中,哪個是類別、哪個是物件、哪個是傳給建構子的引數?

參考答案

Student 是類別;amy 是物件(實例);"Amy" 與 "HL" 是傳給建構子的引數。

練習 2:設計類別

設計一個 BankAccount 類別:私有屬性 owner、balance;方法 deposit(amount)、withdraw(amount)(餘額不足時不允許提款並回傳 False)、get_balance()。

參考答案
class BankAccount:
    def __init__(self, owner, balance=0):
        self.__owner = owner
        self.__balance = balance

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount

    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            return True
        return False

    def get_balance(self):
        return self.__balance
練習 3:封裝的理由

為什麼 BankAccount 的 balance 應設為私有,而不是讓外部直接寫 account.balance = 1000000?

參考答案

私有屬性加上方法控制,可以確保餘額只能透過存款、提款等合法操作改變,並在方法中驗證金額與記錄交易。若外部能直接改值,任何程式碼都能把餘額改成任意數字或負數,資料就失去正確性。

練習 4:靜態屬性

在 BankAccount 中加入一個靜態屬性,記錄總共開了幾個帳戶。

參考答案
class BankAccount:
    total_accounts = 0

    def __init__(self, owner, balance=0):
        self.__owner = owner
        self.__balance = balance
        BankAccount.total_accounts += 1