---
# System prepended metadata

title: 函數與類：何時使用哪個以及為什麼？

---

# 函數與類：何時使用哪個以及為什麼？

## 介紹

在程式設計中，我們通常會遇到一個問題：
何時應該使用具有方法的類別，何時應該在模組中使用函式？
如果選擇不當，你的程式碼可能比需要的更複雜，這使得維護更困難

首先，我們需要更好地理解函式和類別的差異。

- 函式接收輸入參數，然後進行一些操作，並返回結果。你可以將這個結果傳遞給其他函式。在像Haskell這樣的函式語言中，甚至允許你將函式傳遞給函式，或讓函式返回其他函式。(Python 中的 Callable)
- 在面向對象(物件導向)的程式語言，如Java，一切都圍繞著狀態(物件的狀態)。
  - 你有一些變數被組織成對象，這些對象是其他對象的一部分，形成一種階層結構。你甚至可以使用繼承來擴展這些對象結構的定義。


## 當你的程式碼以**行動**為重點時，請使用函式

在這個例子中，我們有一個簡單的函式來分析數據：

```python
def load_data(file_path):
    # 載入數據的實作...
    pass

def analyze_data(data):
    # 分析數據的實作...
    pass

def print_results(results):
    # 打印結果的實作...
    pass

# 使用函式
data = load_data('data.txt')
results = analyze_data(data)
print_results(results)
```

以一個分析數據的簡單應用程序為例，這是一個典型的以行動為主導的程序。我們從載入數據開始，然後進行分析，然後再進行第二次分析，並打印該信息。在這種情況下，函式是一種很好的組織程式碼的方式。

## 當你的程式碼以**狀態**為重點時，請使用類別

在這個例子中，我們有一個模擬銀行帳戶的類別：

```python
class BankAccount:
    def __init__(self, initial_balance):
        self.balance = initial_balance

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient balance!")
        self.balance -= amount
```

銀行帳戶代表著一種狀態，並且我們可以創建該類的多個對象，即多個銀行帳戶。我們可以進行存款和提款操作，這些操作都會改變帳戶的狀態：

```python
account = BankAccount(1000)
account.deposit(500)
account.withdraw(200)
```

更複雜的範例(多個帳戶互相操作)

```python
class BankAccount:
    def __init__(self, initial_balance):
        self.balance = initial_balance

    def deposit(self, amount):
        self.balance += amount

    def withdraw(self, amount):
        if amount > self.balance:
            raise ValueError("Insufficient balance!")
        self.balance -= amount

    def transfer(self, other_account: BankAccount, amount):
        """從此帳戶轉移金額到另一個帳戶"""
        if amount > self.balance:
            raise ValueError("Insufficient balance!")
        self.withdraw(amount)
        other_account.deposit(amount)

# 創建兩個帳戶
account1 = BankAccount(1000)
account2 = BankAccount(500)

# 從 account1 轉移 200 到 account2
account1.transfer(
    other_account=account2, 
    amount=200
)
```

如果我們用函式來解決這個問題，將會更為複雜，因為銀行帳戶更注重狀態而非行動。這就是一種更適合用面向對象程式設計的情況。

的多個對象，即多個銀行帳戶。如果我們用函式來解決這個問題，將會更為複雜，因為銀行帳戶更注重狀態而非行動。這就是一種更適合用面向對象程式設計的情況。

我和其他的文章不一樣，既然說不好，就是要舉例啊
以下是使用函式的範例

使用函式來實現銀行帳戶互轉的功能，可以把帳戶的餘額存放在一個 dictionary 中，然後設計一些函式來對這些帳戶進行操作。以下是一個可能的實現：
```python
def create_account(accounts, name, initial_balance):
    accounts[name] = initial_balance

def deposit(accounts, name, amount):
    accounts[name] += amount

def withdraw(accounts, name, amount):
    if amount > accounts[name]:
        raise ValueError("Insufficient balance!")
    accounts[name] -= amount

def transfer(accounts, from_name, to_name, amount):
    if amount > accounts[from_name]:
        raise ValueError("Insufficient balance!")
    withdraw(accounts, from_name, amount)
    deposit(accounts, to_name, amount)

# 創建兩個帳戶
accounts = {}
create_account(accounts, 'account1', 1000)
create_account(accounts, 'account2', 500)

# 從 account1 轉移 200 到 account2
transfer(accounts, 'account1', 'account2', 200)
```

這種設計的優點和缺點：

優點：

- 簡單：這種設計很簡單，我們只需要一個 dictionary 和一些操作帳戶的函式。
- 與語言無關：這種設計可以在不支持面向對象程式設計的語言中使用。

缺點：

- 難以管理複雜的情況：如果我們需要管理更複雜的帳戶，例如支持信用卡帳戶和儲蓄帳戶，那麼使用這種設計就變得更困難。我們可能需要添加更多的函式，或者更改現有的函式，這可能導致程式碼變得難以維護。
- 無法利用面向對象的特性：這種設計無法利用面向對象程式設計的一些特性，例如封裝、繼承和多型性。例如，我們無法為帳戶添加新的屬性或方法，除非我們更改所有的函式。

看起來好像也沒有複雜很多對吧
對！因為以太坊區塊鏈的貨幣轉移就是這樣運作的，人家運做的很好啊
但假設你考慮進去很多因素：

ex 

- 一個帳號有台幣/美金/日圓
- 每天有提領上限
- 有 VIP 客戶有特殊權限

可能就會覺得用函數去發想有點複雜了吧

這邊我覺得任何程式的寫法都是一種取捨
沒有一定好壞之分
只有在你的情況下，哪種寫法比較適合你

總的來說，如果你的應用程式足夠簡單，使用函式來實現銀行帳戶互轉可能是一種好的選擇。然而，如果你需要管理更複雜的帳戶，或者你想要利用面向對象程式設計的特性，那麼使用類別可能是更好的選擇。

當然，Python 等語言可以靈活地使用這兩種方法。在許多情況下，使用函式和類別的組合會更有意義。如果你的程序更關注信息的流動，那麼使用更多的函式會更好；如果你的程序更關注狀態，那麼使用更多的類別會更好。
但也別忘了，實驗並嘗試不同的方法，可以幫助你更好地理解這些主題，並最終獲得更好的結果。
我是很喜歡用不同方式寫同一種東西啦，但在工作上有時間壓力又是另一回事了 !

我是一個喜歡分享的後端工程師，這裡會分享我所見所學，都是軟體相關的知識啦
可能比較多想法的部分，有舉例的話我會盡量活潑有趣的舉例
我會盡量用最簡單的方式來解釋，如果有任何問題都可以留言給我